[rlplot] 11/23: Imported Upstream version 1.2

Andreas Tille tille at debian.org
Wed Jun 29 09:50:56 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository rlplot.

commit 26b828ca428cfa6d25d6a29a6c2d35ef20790bb5
Author: Andreas Tille <tille at debian.org>
Date:   Wed Jun 29 11:43:56 2016 +0200

    Imported Upstream version 1.2
---
 Axes.cpp        |    79 +-
 Export.cpp      |    99 +-
 Fileio.cpp      |  6136 +++++++++----------
 ODbuttons.cpp   |     8 +-
 Output.cpp      |    53 +-
 PlotObs.cpp     |   443 +-
 PropertyDlg.cpp |  1751 +++---
 QT_Spec.cpp     |  4657 +++++++--------
 QT_Spec.h       |     2 +
 RLPLOT.RC       |     2 +
 TheDialog.cpp   |   511 +-
 TheDialog.h     |    29 +-
 UtilObj.cpp     |   712 ++-
 Utils.cpp       |   314 +-
 Version.h       |     2 +-
 WinSpec.cpp     |   220 +-
 exprlp.cpp      |   410 +-
 menu.h          |     8 +-
 mfcalc.cpp      |  1396 +++--
 mfcalc.y        |   470 +-
 no_gui.cpp      |    30 +-
 reports.cpp     |   902 ++-
 rlp_math.cpp    |   406 +-
 rlplot.cpp      | 17266 +++++++++++++++++++++++++++++-------------------------
 rlplot.h        |  4827 +++++++--------
 rlplot.spec     |     6 +-
 spreadwi.cpp    |  3073 +++++-----
 use_gui.cpp     |   230 +-
 28 files changed, 24389 insertions(+), 19653 deletions(-)

diff --git a/Axes.cpp b/Axes.cpp
index b446a0c..559fbc4 100755
--- a/Axes.cpp
+++ b/Axes.cpp
@@ -154,6 +154,10 @@ GridLine::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SET_DATAOBJ:
 		Id = GO_GRIDLINE;
 		return true;
+	case CMD_SCALE:
+		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
 	case CMD_SETSCROLL:
 	case CMD_SET_GO3D:
 	case CMD_REDRAW:
@@ -501,8 +505,7 @@ Tick::SetSize(int select, double value)
 	case SIZE_AXIS_TICKS:
 		size = value;
 		break;
-	case SIZE_LB_XDIST:
-	case SIZE_LB_YDIST:
+	case SIZE_LB_XDIST:		case SIZE_LB_YDIST:
 		if(label)return label->SetSize(select, value);
 		break;
 	case SIZE_TICK_ANGLE:
@@ -547,6 +550,11 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 	AxisDEF *axis;
 
 	switch(cmd){
+	case CMD_SCALE:
+		if(label) label->Command(cmd, tmpl, o);
+		if(Grid) Grid->Command(cmd, tmpl, o);
+		size *= ((scaleINFO*)tmpl)->sy.fy;
+		break;
 	case CMD_SET_AXDEF:
 		if(axis = (AxisDEF*)tmpl) {
 			flags = (flags & AXIS_MINORTICK) | axis->flags;
@@ -641,7 +649,7 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 		LabelDef->ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
 		LabelDef->ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
 		LabelDef->RotBL = LabelDef->RotCHAR = 0.0f;
-		LabelDef->fSize = parent ? parent->GetSize(SIZE_TICK_LABELS) : defs.GetSize(SIZE_TICK_LABELS);
+		LabelDef->fSize = parent ? parent->GetSize(SIZE_TICK_LABELS) : DefSize(SIZE_TICK_LABELS);
 		switch(flags & 0x70) {
 		case AXIS_USER:		LabelDef->Align = TXA_VCENTER | TXA_HCENTER;	break;
 		case AXIS_LEFT:		LabelDef->Align = TXA_VCENTER | TXA_HRIGHT;		break;
@@ -653,7 +661,7 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 		LabelDef->Style = TXS_NORMAL;
 		LabelDef->Mode = TXM_TRANSPARENT;
 		LabelDef->Font = FONT_HELVETICA;
-		LabelDef->text = tmpl && *((char*)tmpl) ? strdup((char*)tmpl) : 0L;
+		LabelDef->text = tmpl && *((char*)tmpl) ? _strdup((char*)tmpl) : 0L;
 		label = new Label(this, 0L, fix, fiy, LabelDef, LB_X_PARENT | LB_Y_PARENT);
 		if(LabelDef->text) free(LabelDef->text);
 		delete (LabelDef);
@@ -671,6 +679,7 @@ Tick::DoPlot(double six, double csx, anyOutput *o)
 	if(!parent || parent->Id != GO_AXIS) return;
 	if(mo) DelBitmapClass(mo);		mo = 0L;
 	if(ls) delete(ls);				ls = 0L;
+	ip2.x = ip2.y = ip2.z = 0;
 	if(!((Axis*)parent)->GetValuePos(value, &fix, &fiy, &fiz, o))return;
 	lbx = fix;		lby = fiy;
 	if(flags & AXIS_ANGULAR) {
@@ -678,8 +687,8 @@ Tick::DoPlot(double six, double csx, anyOutput *o)
 		dp1.fy = o->co2fiy(parent->GetSize(SIZE_YCENT)+parent->GetSize(SIZE_GRECT_TOP));
 		dp1.fz = o->un2fix(parent->GetSize(SIZE_DRADIUS));
 		six = (fix - dp1.fx)/dp1.fz;		csx = (dp1.fy - fiy)/dp1.fz;
-		lbx += (o->un2fix(defs.GetSize(SIZE_AXIS_TICKS)*3.0*six));
-		lby -= (o->un2fiy(defs.GetSize(SIZE_AXIS_TICKS)*3.0*csx));
+		lbx += (o->un2fix(DefSize(SIZE_AXIS_TICKS)*3.0*six));
+		lby -= (o->un2fiy(DefSize(SIZE_AXIS_TICKS)*3.0*csx));
 		}
 	switch(type & 0x0f) {
 	case 1:		lsi = sin(angle/57.29577951);	lcsi = cos(angle/57.29577951);	break;
@@ -829,11 +838,12 @@ Axis::GetSize(int select)
 	case SIZE_YCENT:			return axis->Center.fy;
 	case SIZE_RADIUS1:	case SIZE_RADIUS2:	case SIZE_DRADIUS:
 		return axis->Radius;
+	case SIZE_BOUNDS_XMIN:		case SIZE_BOUNDS_XMAX:		case SIZE_BOUNDS_YMIN:
+	case SIZE_BOUNDS_YMAX:		case SIZE_BOUNDS_ZMIN:		case SIZE_BOUNDS_ZMAX:
+		if(parent) return parent->GetSize(select);
+		break;
 		}
-	//DEBUG: we should return a reasonable value for SIZE_BOUNDS_...
-	//    if the axis is not scaling (i.e. parent == this).
-	if(parent) return parent->GetSize(select);
-	else return defs.GetSize(select);
+	return DefSize(select);
 }
 
 DWORD
@@ -864,10 +874,8 @@ Axis::SetSize(int select, double value)
 		lbdist.fy = value;
 		if(axisLabel)axisLabel->SetSize(select,value);
 		break;
-	case SIZE_TLB_XDIST:
-	case SIZE_TLB_YDIST:
-	case SIZE_AXIS_TICKS:
-	case SIZE_TICK_ANGLE:
+	case SIZE_TLB_XDIST:		case SIZE_TLB_YDIST:
+	case SIZE_AXIS_TICKS:		case SIZE_TICK_ANGLE:
 		switch (select){
 		case SIZE_TLB_XDIST:
 			tlbdist.fx = value;			select = SIZE_LB_XDIST;
@@ -1157,7 +1165,7 @@ Axis::DoMark(anyOutput *o, bool mark)
 {
 	LineDEF mrkLine;
 	int x1, y1, x2, y2;
-	double minw = defs.GetSize(SIZE_DATA_LINE);
+	double minw = DefSize(SIZE_DATA_LINE);
 
 	if(axis->flags & AXIS_ANGULAR) {
 		if(mark) {
@@ -1196,16 +1204,34 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 	MouseEvent *mev;
 	GraphObj **tmpPlots;
 	void *sv_ptr;
+	scaleINFO *scale;
 	int i;
 
 	switch (cmd) {
+	case CMD_SCALE:
+		scale = (scaleINFO*)tmpl;
+		lbdist.fx *= scale->sx.fy;			lbdist.fy *= scale->sy.fy;
+		tlbdist.fx *= scale->sx.fy;			tlbdist.fy *= scale->sy.fy;
+		sizAxTickLabel *= scale->sy.fy;		sizAxTick *= scale->sy.fy;
+		sizAxLine *= scale->sy.fy;			brksymsize *= scale->sy.fy;
+		brkgap *= scale->sy.fy;				GridLine.patlength *= scale->sy.fy;
+		GridLine.width *= scale->sy.fy;		tlbdef.fSize *= scale->sy.fy;
+		axis->loc[0].fx *= scale->sx.fy;	axis->loc[1].fx *= scale->sx.fy;
+		axis->loc[0].fy *= scale->sy.fy;	axis->loc[1].fy *= scale->sy.fy;
+		axis->loc[0].fz *= scale->sz.fy;	axis->loc[1].fz *= scale->sz.fy;
+		axis->Center.fx *= scale->sx.fy;	axis->Center.fy *= scale->sy.fy;
+		axis->Radius *= scale->sy.fy;		tlbdef.iSize = 0;
+		if(axisLabel) axisLabel->Command(cmd, tmpl, o);
+		if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
+		if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+		return true;
 	case CMD_HIDE_MARK:
 		if(!tmpl || !o) return false;
 		if(tmpl == (void*)axisLabel){
 			axisLabel->DoMark(o, false);
 			return true;
 			}
-		if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++) {
+		if(Ticks) for(i = 0; i < NumTicks; i++) {
 			if(Ticks[i]) {
 				if(tmpl == (void*)Ticks[i]) {
 					Ticks[i]->DoMark(o, false);
@@ -1354,7 +1380,6 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		if(scaleOut) delete(scaleOut);
 		scaleOut = drawOut = 0L;
-		axis->Start = axis->min;
 		return true;
 	case CMD_AUTOSCALE:		//we receive this command to update ticks after rescaling
 		if(axis && (AxisDEF*)tmpl == axis && (axis->flags & AXIS_AUTOSCALE) && 
@@ -1386,9 +1411,9 @@ Axis::SetTick(long idx, double val, DWORD flags, char *txt)
 	Ticks[idx] = new Tick(this, data, val, flags);
 	if(!txt) {
 		WriteNatFloatToBuff(TmpTxt, val);
-		l = strdup(TmpTxt+1);
+		l = _strdup(TmpTxt+1);
 		}
-	else l = strdup(txt);
+	else l = _strdup(txt);
 	if(!gl_type) {
 		}
 	if(Ticks[idx]) {
@@ -1460,7 +1485,11 @@ Axis::CreateTicks()
 		if(!Ticks) return;
 		for(NumTicks = 0; NumTicks < nstep && fVal <= axis->max;
 			NumTicks++, fVal += axis->Step) {
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
+#else
 			sprintf(TmpTxt, format, fVal);
+#endif
 			SetTick(NumTicks, fVal, axis->flags, TmpTxt);
 			}
 		}
@@ -1479,12 +1508,20 @@ Axis::ManuTicks(double sa, double st, int n, DWORD flags)
 	format = GetNumFormat(floor(log10(st)));
 	Ticks = (Tick**)calloc(m, sizeof(Tick*));
 	for(NumTicks = 0, fVal = sa; NumTicks < m && fVal <= axis->max; NumTicks++) {
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
+#else
 		sprintf(TmpTxt, format, fVal);
+#endif
 		SetTick(NumTicks, fVal, flags, TmpTxt);
 		for(j = 0; j < n; j++) {
 			mival = fVal+mist*(double)j +mist;
 			if(mival < axis->max) {
+#ifdef USE_WIN_SECURE
+				sprintf_s(TmpTxt, TMP_TXT_SIZE, format, mival);
+#else
 				sprintf(TmpTxt, format, mival);
+#endif
 				NumTicks++;
 				SetTick(NumTicks, mival, flags | AXIS_MINORTICK, TmpTxt);
 				}
@@ -1496,7 +1533,7 @@ Axis::ManuTicks(double sa, double st, int n, DWORD flags)
 bool
 Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *op)
 {
-	double tmp1;
+	double tmp1 = 1.0;
 	int i;
 	bool bRet = true;
 	anyOutput *o;
@@ -1546,7 +1583,7 @@ Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *
 		*fix = flim[1].fx + tmp1*(flim[0].fx - flim[1].fx);
 		*fiy = flim[1].fy + tmp1*(flim[0].fy - flim[1].fy);
 		}
-	if(tmp1 < -.005f || tmp1 > 1.005) return false;
+	if(tmp1 < -.005 || tmp1 > 1.005) return false;
 	return bRet;
 }
 
diff --git a/Export.cpp b/Export.cpp
index 86107e6..7fd0ea2 100755
--- a/Export.cpp
+++ b/Export.cpp
@@ -25,6 +25,9 @@
 #include <math.h>
 #include <fcntl.h>				//file open flags
 #include <sys/stat.h>			//I/O flags
+#ifdef USE_WIN_SECURE
+	#include <share.h>			//I/O flags
+#endif
 
 #ifdef _WINDOWS
 	#include <io.h>					//for read/write
@@ -105,7 +108,7 @@ ExportWMF::ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags)
 	hPen = 0xffff, hBrush = 0xffff, hFont = 0xffff;
 	hres = vres = res;
 	go = g;
-	if(FileName)name = strdup(FileName);
+	if(FileName)name = _strdup(FileName);
 	else name = 0L;
 	oFile = 0;
 	rec_size = 28;
@@ -220,8 +223,13 @@ ExportWMF::StartPage()
 {
 	if(!go) return false;
 	if(name) {
+#ifdef USE_WIN_SECURE
+		if(0 !=(_sopen_s(&oFile, name, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _SH_DENYNO,
+			_S_IWRITE | _S_IREAD))) {
+#else
 		if(-1 ==(oFile = open(name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
 			S_IWRITE | S_IREAD))) {
+#endif
 			ErrorBox("Could not open output file");
 			return false;
 			}
@@ -231,7 +239,7 @@ ExportWMF::StartPage()
 		}
 	VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
 	VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
-	write(oFile, &header, 18);
+	_write(oFile, &header, 18);
 	return true;
 }
 
@@ -240,15 +248,15 @@ ExportWMF::EndPage()
 {
 	unsigned short end_token[3] = {3, 0, 0};
 
-	write(oFile, &end_token, 6);
-	file_size = lseek(oFile, 0L, SEEK_CUR);
-	lseek(oFile, 0L, SEEK_SET);
+	_write(oFile, &end_token, 6);
+	file_size = _lseek(oFile, 0L, SEEK_CUR);
+	_lseek(oFile, 0L, SEEK_SET);
 	header.mtSize0 = (file_size>>1)&0xffff;
 	header.mtSize1 = file_size>>17;
 	header.mtNoObj = maxGDIobj;
 	header.mtMaxRec = rec_size;
-	write(oFile, &header, 18);
-	oFile = close(oFile);
+	_write(oFile, &header, 18);
+	oFile = _close(oFile);
 	return true;
 }
 
@@ -297,7 +305,7 @@ ExportWMF::oTextOut(int x, int y, char *txt, int cb)
 		TXA_HCENTER) ? 6 : 0) | ((TxtSet.Align & TXA_VBOTTOM) ?	8 : 0));
 	wmfSetBkMode(TxtSet.Mode ? 1 : 2);
 	wmfTextOut(x, (TxtSet.Align & TXA_VCENTER) ? y - TxtSet.iSize/2 : y, txt, 
-		(cb > 0) ? cb : strlen(txt));
+		(unsigned short)((cb > 0) ? cb : strlen(txt)));
 	return true;
 }
 
@@ -359,7 +367,7 @@ ExportWMF::wmfCreateSolidBrush(DWORD color)
 {
 	wmfLogBrush lb = {7, 0x2fc, 0, color, 0};
 
-	write(oFile, &lb, 14);
+	_write(oFile, &lb, 14);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -376,8 +384,8 @@ ExportWMF::wmfCreateFontIndirect(short lfHeight, short lfWidth, short lfEscapeme
 		lfItalic, lfUnderline, lfStrikeOut, lfCharSet, lfOutPrecision, lfClipPrecision,
 		lfQuality, lfPitchAndFamily, "Arial"};
 
-	if(FaceName && FaceName[0]) strcpy(lf.face, FaceName);
-	write(oFile, &lf, 56);
+	if(FaceName && FaceName[0]) rlp_strcpy(lf.face, 32, FaceName);
+	_write(oFile, &lf, 56);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -388,7 +396,7 @@ ExportWMF::wmfCreateSolidPen(DWORD color, unsigned short width)
 {
 	wmfLogPen lp = {8, 0x2fa, 0, width, color};
 
-	write(oFile, &lp, 16);
+	_write(oFile, &lp, 16);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -410,7 +418,7 @@ ExportWMF::wmfEllipse(unsigned short ix1, unsigned short iy1, unsigned short ix2
 {
 	wmfRect rc = {7, 0x418, iy2, ix2, iy1, ix1};
 	
-	write(oFile, &rc, 14);
+	_write(oFile, &rc, 14);
 }
 
 void
@@ -420,11 +428,11 @@ ExportWMF::wmfPolyline(POINT *pts, unsigned short cp)
 	unsigned short v[2];
 	int i;
 
-	write(oFile, &pl, 8);
+	_write(oFile, &pl, 8);
 	for(i = 0; i < cp; i++) {
 		v[0] = (unsigned short)pts[i].x;
 		v[1] = (unsigned short)pts[i].y;
-		write(oFile, &v, 4);
+		_write(oFile, &v, 4);
 		}
 	if(pl.Size > rec_size) rec_size = pl.Size;
 }
@@ -436,11 +444,11 @@ ExportWMF::wmfPolygon(POINT *pts, unsigned short cp)
 	unsigned short v[2];
 	int i;
 
-	write(oFile, &pl, 8);
+	_write(oFile, &pl, 8);
 	for(i = 0; i < cp; i++) {
 		v[0] = (unsigned short)pts[i].x;
 		v[1] = (unsigned short)pts[i].y;
-		write(oFile, &v, 4);
+		_write(oFile, &v, 4);
 		}
 	if(pl.Size > rec_size) rec_size = pl.Size;
 }
@@ -450,7 +458,7 @@ ExportWMF::wmfRectangle(unsigned short ix1, unsigned short iy1, unsigned short i
 {
 	wmfRect rc = {7, 0x41B, iy2, ix2, iy1, ix1};
 	
-	write(oFile, &rc, 14);
+	_write(oFile, &rc, 14);
 }
 
 void
@@ -458,7 +466,7 @@ ExportWMF::wmfSelectObject(unsigned short o)
 {
 	wmfObjShort so  = {4, 0x12D, o};
 
-	write(oFile, &so, 8);
+	_write(oFile, &so, 8);
 }
 
 void
@@ -466,8 +474,8 @@ ExportWMF::wmfSetBkColor(DWORD col)
 {
 	wmfObjCol co = {5, 0x201};
 
-	write(oFile, &co, 6);
-	write(oFile, &col, 4);
+	_write(oFile, &co, 6);
+	_write(oFile, &col, 4);
 }
 
 void
@@ -476,9 +484,9 @@ ExportWMF::wmfSetBkMode(unsigned m)
 	wmfObjShort mo = {5, 0x102, m & 0xffff};
 	unsigned short p;
 
-	write(oFile, &mo, 8);
+	_write(oFile, &mo, 8);
 	p = m>>16;
-	write(oFile, &p, 2);
+	_write(oFile, &p, 2);
 }
 
 //cmSetMapMode()
@@ -490,9 +498,9 @@ ExportWMF::wmfSetTextAlign(unsigned a)
 	wmfObjShort ao = {5, 0x12E, a & 0xffff};
 	unsigned short p;
 
-	write(oFile, &ao, 8);
+	_write(oFile, &ao, 8);
 	p = a>>16;
-	write(oFile, &p, 2);
+	_write(oFile, &p, 2);
 }
 
 void
@@ -500,8 +508,8 @@ ExportWMF::wmfSetTextColor(DWORD col)
 {
 	wmfObjCol tc = {5, 0x209};
 
-	write(oFile, &tc, 6);
-	write(oFile, &col, 4);
+	_write(oFile, &tc, 6);
+	_write(oFile, &col, 4);
 }
 
 //cmSetWindowExt()
@@ -515,9 +523,9 @@ ExportWMF::wmfTextOut(unsigned short ix1, unsigned short iy1, char *txt, unsigne
 
 	le = cb &1 ? cb+1 : cb;
 	to.Size += le>>1;
-	write(oFile, &to, 8);
-	write(oFile, txt, le);
-	write(oFile, &v, 4);	
+	_write(oFile, &to, 8);
+	_write(oFile, txt, le);
+	_write(oFile, &v, 4);	
 	if(to.Size > rec_size) rec_size = to.Size;
 }
 
@@ -582,12 +590,12 @@ ExportSVG::ExportSVG(GraphObj *g, char *FileName, DWORD flg)
 	dFillCol = 0xffffffffL;
 	hres = vres = 1000.0f;
 	go = g;
-	if(FileName)name = strdup(FileName);
+	if(FileName)name = _strdup(FileName);
 	else name = 0L;
 	oFile = 0L;
 	flags = flg;
-	strcpy(indent, "   ");
-	strcpy(tHatchStyle, "style=\"stroke:black; stroke-width:1\"");
+	rlp_strcpy(indent, 80, "   ");
+	rlp_strcpy(tHatchStyle, 80, "style=\"stroke:black; stroke-width:1\"");
 	bUseGroupLine = false;
 }
 
@@ -620,8 +628,13 @@ ExportSVG::SetFill(FillDEF *fill)
 		if(hgo) hgo->SetFill(fill);
 		if(fill->hatch) {
 			if(1 >(iL  = iround(un2fix(fill->hatch->width)))) iL = 1;
+#ifdef USE_WIN_SECURE
+			sprintf_s(tHatchStyle, 80, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
+				ColName(fill->hatch->color), iL);
+#else
 			sprintf(tHatchStyle, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
 				ColName(fill->hatch->color), iL);
+#endif
 			}
 		}
 	else {
@@ -655,7 +668,11 @@ ExportSVG::StartPage()
 	h = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
 	w++; h++;
 	if(name) {
+#ifdef USE_WIN_SECURE
+		fopen_s(&oFile, name, "w");
+#else
 		oFile = fopen(name, "w");
+#endif
 		if(!oFile) {
 			ErrorBox("Could not open\noutput file!");
 			return false;
@@ -744,7 +761,7 @@ ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
 			sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
 			AddToOutput(tmptxt);
 			}
-		i = strlen(output);
+		i = (int)strlen(output);
 		if(i) output[i-1] = 0;
 		strcat(output, "\"");
 		if(!bUseGroupLine) {
@@ -900,7 +917,7 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 		sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
 		AddToOutput(tmptxt);
 		}
-	i = strlen(output);
+	i = (int)strlen(output);
 	if(i) output[i-1] = 0;
 	strcat(output, "\" ");
 	sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
@@ -928,7 +945,7 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 void
 ExportSVG::Indent(bool ind)
 {
-	int i = strlen(indent);
+	int i = (int)strlen(indent);
 
 	if(i > 20 && ind) return;
 	if(ind) strcat(indent, "   ");
@@ -1313,16 +1330,16 @@ char *
 ExportEPS::col2eps(DWORD color)
 {
 	static char txt[50];
-	char tmptxt[10];
 	float r, g, b;
 
 	r = (float)(color & 0xff)/255.0f;
 	g = (float)((color>>8)&0xff)/255.0f;
 	b = (float)((color>>16)&0xff)/255.0f;
-	WriteFloatToBuff(tmptxt, r);	strcpy(txt, tmptxt+1);
-	WriteFloatToBuff(tmptxt, g);	strcat(txt, tmptxt);
-	WriteFloatToBuff(tmptxt, b);	strcat(txt, tmptxt);
-	strcat(txt, " setrgbcolor");
+#ifdef USE_WIN_SECURE
+	sprintf_s(txt, 50, "%g %g %g setrgbcolor", r, g, b);
+#else
+	sprintf(txt, "%g %g %g setrgbcolor", r, g, b);
+#endif
 	return txt;
 }
 
diff --git a/Fileio.cpp b/Fileio.cpp
index fc7a5d5..7fa8a37 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -1,935 +1,1029 @@
-//FileIO.cpp, Copyright (c) 2001-2006 R.Lackner
-//read/write graphic objects
-//
-//    This file is part of RLPlot.
-//
-//    RLPlot 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.
-//
-//    RLPlot 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 RLPlot; if not, write to the Free Software
-//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-//
-#include "rlplot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include <ctype.h>
-#include <fcntl.h>				//file open flags
-#include <sys/stat.h>			//I/O flags
-
-#ifdef _WINDOWS
-	#include <io.h>					//for read/write
-#else
-	#define O_BINARY 0x0
-	#include <unistd.h>
-#endif
-
-extern GraphObj *CurrGO;			//Selected Graphic Objects
-extern Default defs;
-extern int dlgtxtheight;
-extern char TmpTxt[];
+//FileIO.cpp, Copyright (c) 2001-2006 R.Lackner
+//read/write graphic objects
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot 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.
+//
+//    RLPlot 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 RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <ctype.h>
+#include <fcntl.h>				//file open flags
+#include <sys/stat.h>			//I/O flags
+
+#ifdef _WINDOWS
+	#include <io.h>					//for read/write
+#else
+	#define O_BINARY 0x0
+	#include <unistd.h>
+#endif
+
+extern GraphObj *CurrGO;			//Selected Graphic Objects
+extern Default defs;
+extern int dlgtxtheight;
+extern char TmpTxt[];
 extern int cPlots;
-
-static notary *Notary = 0L;
-static ReadCache *Cache = 0L;
-
-unsigned long cObsW;				//count objects written
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// graphic input/output is driven by tables based on the descIO template
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-typedef struct {
-	char *label;
-	unsigned short type;
-	void *ptr;
-	long *count;
-	}descIO;
-
-//the type member of descIO describes the following data types pointed to by ptr
-enum {typNONE, typNZINT, typINT, typLFLOAT, typNZLFLOAT, 
-	typDWORD, typULONG, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
-	typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ,	typOBJLST,
-	typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF, 
-	typLAST = 0x100};
-
+GraphObj *LastOpenGO;
+
+static notary *Notary = 0L;
+static ReadCache *Cache = 0L;
+
+unsigned long cObsW;				//count objects written
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// graphic input/output is driven by tables based on the descIO template
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct {
+	char *label;
+	unsigned short type;
+	void *ptr;
+	long *count;
+	}descIO;
+
+//the type member of descIO describes the following data types pointed to by ptr
+enum {typNONE, typNZINT, typINT, typLFLOAT, typNZLFLOAT, 
+	typDWORD, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
+	typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ,	typOBJLST,
+	typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF, 
+	typLAST = 0x100};
+
 static char *ptr =0L;
-static long ptr_step = 2048;
-static int cbOut, sizeOut = 0, iFile = 0;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// output graph to file, elementary functions
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-int OpenOutputFile(char *file)
-{
-	time_t ti;
-
-	if(ptr) free(ptr);
-	ptr = 0L;	cbOut = 0;
-	if(file && BackupFile(file)) {
-		if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
-			S_IWRITE | S_IREAD))) return -1;
-		ptr = (char *)malloc(sizeOut = 2048);
-		if(!ptr) goto openerr;
-		ti = time(0L);
-		cbOut = sprintf(ptr,";RLP 1.0\n;File \"%s\" created by RLPlot version "
-			""SZ_VERSION" for %s \n;Date/Time: %s ",
-			file,  
+static int cbOut, sizeOut = 0, iFile = -1;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// output graph to file, elementary functions
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static int OpenOutputFile(char *file)
+{
+	time_t ti;
+
+	if(ptr) free(ptr);
+	ptr = 0L;		cbOut = 0;		ti = time(0L);
+	if(file && BackupFile(file)) {
+#ifdef USE_WIN_SECURE
+		if(_sopen_s(&iFile, file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 
+			0x40, S_IWRITE) || iFile < 0){
+			ErrorBox("Open failed for output file");
+			return -1;
+			}
+#else
+		if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+			S_IWRITE | S_IREAD))){
+			ErrorBox("Open failed for output file");
+			return -1;
+			}
+#endif
+		ptr = (char *)malloc(sizeOut = 2000);
+		if(!ptr) goto openerr;
+		cbOut = rlp_strcpy(ptr, 20, ";RLP 1.0\n;File \"");
+		add_to_buff(&ptr, &cbOut, &sizeOut, file, 0);
+		add_to_buff(&ptr, &cbOut, &sizeOut, "\" created by RLPlot version "SZ_VERSION" for ", 0);
 #ifdef _WINDOWS
-			"Windows",
+		add_to_buff(&ptr, &cbOut, &sizeOut, "Windows", 7);
+#else
+		add_to_buff(&ptr, &cbOut, &sizeOut, "Qt", 2);
+#endif
+		add_to_buff(&ptr, &cbOut, &sizeOut, "\n;Date/Time: ", 13);
+#ifdef USE_WIN_SECURE
+		ctime_s(ptr+cbOut, 30, &ti);	cbOut += 25;
+#else
+		add_to_buff(&ptr, &cbOut, &sizeOut, ctime(&ti), 25);
+#endif
+		}
+	return iFile;
+openerr:
+	ptr = 0L;	cbOut = sizeOut = 0;
+#ifdef USE_WIN_SECURE
+	if(iFile >=0) _close(iFile);
+#else
+	if(iFile >=0) close(iFile);
+#endif
+	return iFile = -1;
+}
+
+static void CloseOutputFile()
+{
+	if(iFile >= 0){
+#ifdef USE_WIN_SECURE
+		if(cbOut) _write(iFile, ptr, cbOut);
+		_close(iFile);
 #else
-			"Qt",
+		if(cbOut) write(iFile, ptr, cbOut);
+		close(iFile);
 #endif
-			ctime(&ti));
-		}
-	return iFile;
-openerr:
-	ptr = 0L;	cbOut = sizeOut = 0;
-	close(iFile);
-	iFile = 0;
-	return -1;
-}
-
-void CloseOutputFile()
-{
-	if(iFile > 0){
-		if(cbOut) write(iFile, ptr, cbOut);
-		close(iFile);
-		}
-	if(ptr) free(ptr);
-	cbOut = sizeOut = 0;
-	ptr = 0L;
-}
-
-void AddStringToOutput(char *str, int length)
-{
-	int i;
-	char *tmp_ptr;
-
-	if((cbOut+length)< sizeOut) {			//fit in buffer
-		memcpy(ptr+cbOut, str, length);
-		cbOut += length;
-		}
-	else if(iFile > 0){						//buffer full: write to file
-		i = sizeOut-cbOut;
-		memcpy(ptr+cbOut, str, i);
-		write(iFile, ptr, 2048);
-		memcpy(ptr, str+i, length-i);
-		cbOut = length-i;
-		}
-	else {									//buffer full: resize buffer
-		if(tmp_ptr = (char*)realloc(ptr, sizeOut+ptr_step)){
-			ptr = tmp_ptr;		sizeOut += ptr_step;	ptr_step += (ptr_step >> 1);
-			AddStringToOutput(str, length);
-			}
-		}
-}
-
-void WriteTypObjLst(GraphObj **ptr, int count)
-{
-	int i, j, c, n;
-	char tmp[512];
-	
-	if(!ptr) return;
-	for(i = c = 0; i <= count/16; i++) {
-		if(i) c =  sprintf(tmp, "   ");
-		for(j = 0; (n=i*16+j) <count && j < 16; j++) {
-			c += sprintf(tmp+c, "%s%ld", j ? " " : "", Notary->RegisterGO(ptr[n]));
-			}
-		if(n >= count) c += sprintf(tmp+c, "}");
-		c += sprintf(tmp+c, "\n");
-		AddStringToOutput(tmp, c);
-		}
-}
-
-void WriteTypIpLst(POINT *ptr, long count)
-{
-	long i, j, c, n;
-	char tmp[256];
-
-	if(!ptr) return;
-	for(i = 0; i <= count/8; i++) {
-		for(j = c = 0; (n =i*8+j) <count && j < 8; j++) {
-			c += sprintf(tmp+c, " %ld", ptr[n].x);
-			c += sprintf(tmp+c, " %ld", ptr[n].y);
-			}
-		if(n >= count) c += sprintf(tmp+c, "}");
-		c += sprintf(tmp+c, "\n");
-		AddStringToOutput(tmp, c);
-		}
-}
-
-void WriteTypFpLst(lfPOINT *ptr, long count)
-{
-	long i, j, c, n;
-	char tmp[256];
-
-	if(!ptr) return;
-	for(i = 0; i <= count/8; i++) {
-		for(j = c = 0; (n =i*8+j) <count && j < 8; j++) {
-			c += WriteFloatToBuff(tmp+c, ptr[n].fx);
-			c += WriteFloatToBuff(tmp+c, ptr[n].fy);
-			}
-		if(n >= count) c += sprintf(tmp+c, "}");
-		c += sprintf(tmp+c, "\n");
-		AddStringToOutput(tmp, c);
-		}
-}
-
-void WriteTypFpLst3D(fPOINT3D *ptr, long count)
-{
-	long i, j, c, n;
-	char tmp[256];
-
-	if(!ptr) return;
-	for(i = 0; i <= count/5; i++) {
-		for(j = c = 0; (n =i*5+j) <count && j < 5; j++) {
-			c += WriteFloatToBuff(tmp+c, ptr[n].fx);
-			c += WriteFloatToBuff(tmp+c, ptr[n].fy);
-			c += WriteFloatToBuff(tmp+c, ptr[n].fz);
-			}
-		if(n >= count && j) c += sprintf(tmp+c, "}\n");
-		else if(n < count) c += sprintf(tmp+c, "\n");
-		AddStringToOutput(tmp, c);
-		}
+		}
+	if(ptr) free(ptr);
+	cbOut = sizeOut = 0;
+	ptr = 0L;		iFile = -1;
+}
+
+static void WriteTypObjLst(GraphObj **obs, int c1)
+{
+	int i, j, no, n, *idx;
+	
+	if(!obs || !(idx=(int*)malloc(c1*sizeof(int)))) return;
+	for(i = no = 0; i < c1; i++) {
+		if(j = Notary->RegisterGO(obs[i])) idx[no++] = j;
+		}
+	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+	add_int_to_buff(&ptr, &cbOut, &sizeOut, no, false, 0);
+	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+	for(i = 0; i < no; i += 16) {
+		if(i) add_to_buff(&ptr, &cbOut, &sizeOut, "   ", 3);
+		for(j = 0; (n=i+j) < no && j < 16; j++) {
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, idx[n], j != 0, 0);
+			}
+		if(n >= no) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+		}
+}
+
+static void WriteTypIpLst(POINT *ppt, int count)
+{
+	long i, j, c, n;
+
+	if(!ppt) return;
+	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+	add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+	for(i = 0; i < count; i += 8) {
+		for(j = c = 0; (n = i+j) <count && j < 8; j++) {
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].x, (j != 0), 0);
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].y, true, 0);
+			}
+		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+		}
+}
+
+static void WriteTypFpLst(lfPOINT *ppt, long count, bool bPar)
+{
+	int i, j, n;
+
+	if (bPar){
+		if(!ppt) return;
+		add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+		add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+		add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+		}
+	else {
+		if(!ppt) count = 0;
+		add_int_to_buff(&ptr, &cbOut, &sizeOut, count, true, 0);
+		if(!count) {
+			add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+			return;
+			}
+		add_to_buff(&ptr, &cbOut, &sizeOut, " {", 2);
+		}
+	for(i = 0; i < count; i += 8) {
+		for(j = 0; (n = i+j) <count && j < 8; j++) {
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
+			}
+		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+		}
+}
+
+static void WriteTypFpLst3D(fPOINT3D *ppt, int count)
+{
+	long i, j, c, n;
+
+	if(!ppt) return;
+	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+	add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+	for(i = 0; i < count; i +=5) {
+		for(j = c = 0; (n =i+j) <count && j < 5; j++) {
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fz, true);
+			}
+		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+		}
 }
 
 static char * esc_str = 0L;
 static int esc_str_size = 0;
-int WriteEscString(char *txt, char *buff, int cb)
+static void WriteEscString(char *txt)
 {
 	int i, j, l, lim = 60;
 
-	if(!txt || !txt[0]) return 0;
-	l = strlen(txt);
-	if((l+10) > esc_str_size) esc_str = (char*)realloc(esc_str, esc_str_size = (l+100));
+	if(!txt || !txt[0]) return;
+	l = (int)strlen(txt);
+	if((l+10) > esc_str_size) if(!(esc_str = (char*)realloc(esc_str, esc_str_size = (l+100))))return;
 	j = 0;	esc_str[j++] = '"';
 	for(i = 0; txt[i]; i++) {
 		switch(txt[i]) {
-		case '\\':	j += sprintf(esc_str+j, "\\\\");	break;
-		case '\n':	j += sprintf(esc_str+j, "\\n");		break;
-		default:	esc_str[j++] = txt[i];
+		case '\\':
+			esc_str[j++] = '\\';	esc_str[j++] = '\\';
+			break;
+		case '\n':
+			esc_str[j++] = '\\';	esc_str[j++] = 'n';
+			break;
+		default:	
+			if(txt[i] >= ' ') esc_str[j++] = txt[i];
 			}
 		if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
-		if(j > lim && (l-i) > 5) {
-			j += sprintf(esc_str+j, "\"\\\n   \"");
+		if(j > lim && (l-i) > 3) {
+			esc_str[j++] = '"';		esc_str[j++] = '\\';
+			esc_str[j++] = '\n';	esc_str[j++] = ' ';
+			esc_str[j++] = ' ';		esc_str[j++] = ' ';
+			esc_str[j++] = '"';
 			lim += 60;
 			}
 		}
-	j += sprintf(esc_str+j, "\"\n");
-	return sprintf(buff+cb, "%s", esc_str);
-}
-
-bool ExecOutput(long id, char *Class, descIO *Desc)
-{
-	static char buff[800];
-	int i, cb, last;
-	fRECT *fr;
-	AxisDEF *ax;
-	LineDEF *ld;
-	FillDEF *fd;
-	TextDEF *tx;
-
-	cb = sprintf(buff, "\n[%ld=%s]\n", id, Class);
-	cObsW++;
-	for(i = 0; Desc[i].label; i++) {
-		last = cb;
-		cb += sprintf(buff+cb,"%s=", Desc[i].label);
-		switch(Desc[i].type & 0xff){
-		case typNZINT:
-			if(!(*(int*)Desc[i].ptr)) {
-				cb = last;
-				break;
-				}
-			//if not zero value continue as if int
-		case typINT:
-			cb += sprintf(buff+cb," %d\n", *(int*)Desc[i].ptr);
-			break;
-		case typNZLFLOAT:
-			if(fabs(*((double*)Desc[i].ptr)) < 1.0e-7) {
-				cb = last;
-				break;
-				}
-			//if not zero or negative continue as if float
-		case typLFLOAT:
-			cb += WriteFloatToBuff(buff+cb, *(double*)Desc[i].ptr);
-			cb += sprintf(buff+cb, "\n");
-			break;
-		case typDWORD:
-			cb += sprintf(buff+cb," 0x%08x\n", *(DWORD *)Desc[i].ptr);
-			break;
-		case typULONG:
-			cb += sprintf(buff+cb," %ld\n", *(unsigned long*)Desc[i].ptr);
-			break;
-		case typFRECT:
-			fr = (fRECT*)Desc[i].ptr;
-			cb += WriteFloatToBuff(buff+cb, fr->Xmin);
-			cb += WriteFloatToBuff(buff+cb, fr->Ymax);
-			cb += WriteFloatToBuff(buff+cb, fr->Xmax);
-			cb += WriteFloatToBuff(buff+cb, fr->Ymin);
-			cb += sprintf(buff+cb, "\n");
-			break;
-		case typNZLFPOINT:
-			if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
-				((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
-				cb = last;
-				break;
-				}
-			//if not zero continue as if fPOINT
-		case typLFPOINT:
-			cb += WriteFloatToBuff(buff+cb, ((lfPOINT *)Desc[i].ptr)->fx);
-			cb += WriteFloatToBuff(buff+cb, ((lfPOINT *)Desc[i].ptr)->fy);
-			cb += sprintf(buff+cb, "\n");
-			break;
-		case typPOINT3D:
-			cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fx);
-			cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fy);
-			cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fz);
-			cb += sprintf(buff+cb, "\n");
-			break;
-		case typAXDEF:
-		case typPTRAXDEF:
-			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
-			//we do not set ownership: reconstruct after read
-			cb += sprintf(buff+cb, "0x%08x",  ax->flags);
-			cb += WriteFloatToBuff(buff+cb, ax->min);
-			cb += WriteFloatToBuff(buff+cb, ax->max);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[0].fx);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[0].fy);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[0].fz);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[1].fx);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[1].fy);
-			cb += WriteFloatToBuff(buff+cb, ax->loc[1].fz);
-			cb += WriteFloatToBuff(buff+cb, ax->Start);
-			cb += WriteFloatToBuff(buff+cb, ax->Step);
-			cb += WriteFloatToBuff(buff+cb, ax->Center.fx);
-			cb += WriteFloatToBuff(buff+cb, ax->Center.fy);
-			cb += WriteFloatToBuff(buff+cb, ax->Radius);
-			cb += sprintf(buff+cb," %d", ax->nBreaks);
-			if(ax->nBreaks) {
-				cb += sprintf(buff+cb, " {");
-				AddStringToOutput(buff, cb);
-				cb = 0;
-				WriteTypFpLst(ax->breaks, ax->nBreaks);
-				}
-			cb += sprintf(buff+cb, "\n");
-			break;
-		case typLINEDEF:
-			ld = (LineDEF *)Desc[i].ptr;
-			cb += WriteFloatToBuff(buff+cb, ld->width);
-			cb += WriteFloatToBuff(buff+cb, ld->patlength);
-			cb += sprintf(buff+cb, ld->color ? " 0x%08x" : " 0x0", ld->color);
-			cb += sprintf(buff+cb, ld->pattern ? " 0x%08x\n" : " 0x0\n", ld->pattern);
-			break;
-		case typFILLDEF:
-			fd = (FillDEF *)Desc[i].ptr;
-			//we set the 'hatch' member to zero: reconstruct after read
-			cb += sprintf(buff+cb," %d 0x%08x", fd->type, fd->color);
-			cb += WriteFloatToBuff(buff+cb, fd->scale);
-			cb += sprintf(buff+cb," 0x0 0x%08x\n", fd->color2);
-			break;
-		case typGOBJ:
-			if(*(GraphObj **)(Desc[i].ptr)) cb += 
-				sprintf(buff+cb," %ld\n", Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)));
-			else cb = last;
-			break;
-		case typOBJLST:
-			if(!*(GraphObj ***)(Desc[i].ptr)){
-				cb = last;
-				break;
-				}
-			cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
-			AddStringToOutput(buff, cb);
-			cb = 0;
-			WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
-			break;
-		case typIPLST:
-			if(!*(POINT**)(Desc[i].ptr)){
-				cb = last;
-				break;
-				}
-			cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
-			AddStringToOutput(buff, cb);
-			cb = 0;
-			WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
-			break;
-		case typFPLST:
-			if(!*(lfPOINT**)(Desc[i].ptr)){
-				cb = last;
-				break;
-				}
-			cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
-			AddStringToOutput(buff, cb);
-			cb = 0;
-			WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
-			break;
-		case typFPLST3D:
-			if(!*(fPOINT3D**)(Desc[i].ptr)){
-				cb = last;
-				break;
-				}
-			cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
-			AddStringToOutput(buff, cb);
-			cb = 0;
-			WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
-			break;
-		case typTEXT:
-			if(!*(char**)(Desc[i].ptr)) cb = last;
-			else cb += WriteEscString(*(char**)(Desc[i].ptr), buff, cb);
-			break;
-		case typTXTDEF:
-		case typPTRTXTDEF:
-			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
-			if(!tx) {
-				cb = last;
-				break;
-				}
-			cb += sprintf(buff+cb, " 0x%08x 0x%08x %g %g %g %d %d %d %d", 
-				tx->ColTxt, tx->ColBg, tx->fSize, tx->RotBL, tx->RotCHAR,
-				tx->Align, tx->Mode, tx->Style, tx->Font);
-			if(tx->text) cb += sprintf(buff+cb, " \"%s\"\n", tx->text);
-			else cb += sprintf(buff+cb, "\n");
-			break;
-			}
-		if(Desc[i].type & typLAST) break;
-		}
-	AddStringToOutput(buff, cb);
-	return true;
-}
-
-void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
-{
-	long f[20];
-	int j, k;
-	long i;
-
-	if(!ptr || !first) return;
-	k = sscanf((char*)first, "%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld", 
-		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
-		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
-	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
-		ptr[i].x = f[j];	ptr[i].y = f[j+1];
-		}
-	while (i < count) {
-		if(!Cache->GetInt(&ptr[i].x) || !Cache->GetInt(&ptr[i].y)) return;
-		i++;
-		}
-}
-
-void ReadTypFpLst(lfPOINT *ptr, long count, unsigned char *first)
-{
-	double f[20];
-	int j, k;
-	long i;
-
-	if(!ptr || !first) return;
-	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", 
-		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
-		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
-	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
-		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];
-		}
-	while (i < count) {
-		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy)) return;
-		i++;
-		}
-}
-
-void ReadTypFpLst3D(fPOINT3D *ptr, long count, unsigned char *first)
-{
-	double f[21];
-	int j, k;
-	long i;
-
-	if(!ptr || !first) return;
-	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
-		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
-		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
-	for(i = 0,  j = 0; j < k && i < count; i++, j += 3) {
-		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];		ptr[i].fz = f[j+2];
-		}
-	while (i < count) {
-		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy) ||
-			!Cache->GetFloat(&ptr[i].fz)) return;
-		i++;
-		}
-}
-
-void TranslateEscChar(char *txt)
-{
-	int i, j;
-
-	if(txt && txt[0]) {
-		for(i = j = 0; txt[i]; i++) {
-			if(txt[i] == '\\') {
-				switch(txt[i+1]) {
-				case 'n':
-					txt[j++] = 0x0a;	i++;	break;
-				case 'r':
-					txt[j++] = 0x0d;	i++;	break;
-				case '"':	case 0x27:			case '\\':
-					txt[j++] = txt[++i];		break;
-				default:
-					txt[j++] = txt[i];	break;
-					}
-				}
-			else txt[j++] = txt[i];
-			}
-		txt[j] = 0;
-		}
-}
-
-void AddLines(char **txt)
-{
-	char tmp[1000], *ntxt;
-	bool mlines;
-	int i, j, cb = strlen(*txt);
-
-	do {
-		mlines = false;
-		Cache->ReadLine(tmp, sizeof(tmp));
-		for(i = strlen(tmp); i > 0 &&(tmp[i-1] < 33 || (tmp[i-1] == 
-			'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
-			(mlines = true))); tmp[--i] = 0);
-		for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
-		TranslateEscChar(tmp);
-		if(tmp[0] && (j = strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
-			strcpy(ntxt+cb, tmp+i);
-			cb += j;	*(txt) = ntxt;
-			}
-		} while (mlines);
-}
-
-bool ExecInput(descIO *Desc)
-{
-	char c, tmp[1000], tmp2[20];
-	int i, j, k, l;
-	bool match, mlines;
-	unsigned long il, jl;
-	AxisDEF *ax;
-	POINT *lp;
-	lfPOINT *lfp;
-	fPOINT3D *lfp3d;
-	LineDEF *ld;
-	FillDEF *fd;
-	fRECT *fr;
-	GraphObj **gobs;
-	TextDEF *tx;
-
-	if(!Desc || !Desc[0].label) return false;
-	for(j = k = 0; ; ) {
-		do{
-			c = Cache->Getc();
-			switch (c) {
-			case '[':					//next object
-			case 0:						//probably eof
-				return true;
-			case '}':					//a lists hang over
-				c = Cache->Getc();
-				break;
-				}
-		} while(c <33);
-		for(i = 1, tmp[0] = c; i < sizeof(tmp) && '=' != (tmp[i] = Cache->Getc()); i++){
+	esc_str[j++] = '"';
+	add_to_buff(&ptr, &cbOut, &sizeOut, esc_str, j);
+}
+
+bool ExecOutput(int id, char *Class, descIO *Desc)
+{
+	int i, last;
+	fRECT *fr;
+	AxisDEF *ax;
+	LineDEF *ld;
+	FillDEF *fd;
+	TextDEF *tx;
+
+	add_to_buff(&ptr, &cbOut, &sizeOut, "\n[", 2);
+	add_int_to_buff(&ptr, &cbOut, &sizeOut, id, false, 0);
+	add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
+	add_to_buff(&ptr, &cbOut, &sizeOut, Class, 0);
+	add_to_buff(&ptr, &cbOut, &sizeOut, "]\n", 2);
+	cObsW++;
+	for(i = 0; Desc[i].label; i++) {
+		if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+		last = cbOut;
+		add_to_buff(&ptr, &cbOut, &sizeOut, Desc[i].label, 0);
+		add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
+		switch(Desc[i].type & 0xff){
+		case typNZINT:
+			if(!(*(int*)Desc[i].ptr)) {
+				cbOut = last;			break;
+				}
+			//if not zero value continue as if int
+		case typINT:
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, *(int*)Desc[i].ptr, true, 0);
+			break;
+		case typNZLFLOAT:
+			if(*((double*)Desc[i].ptr) == 0.0) {
+				cbOut = last;			break;
+				}
+			//if not zero or negative continue as if float
+		case typLFLOAT:
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, *(double*)Desc[i].ptr, true);
+			break;
+		case typDWORD:
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, *(DWORD *)Desc[i].ptr, true);
+			break;
+		case typFRECT:
+			fr = (fRECT*)Desc[i].ptr;
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmin, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymax, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmax, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymin, true);
+			break;
+		case typNZLFPOINT:
+			if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
+				((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
+				cbOut = last;			break;
+				}
+			//if not zero continue as if fPOINT
+		case typLFPOINT:
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fx, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fy, true);
+			break;
+		case typPOINT3D:
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fx, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fy, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fz, true);
+			break;
+		case typAXDEF:		case typPTRAXDEF:
+			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+			//we do not set ownership: reconstruct after read
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ax->flags, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->min, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->max, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fx, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fy, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fz, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fx, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fy, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fz, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Start, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Step, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fx, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fy, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Radius, true);
+			WriteTypFpLst(ax->breaks, ax->nBreaks, false);
+			break;
+		case typLINEDEF:
+			ld = (LineDEF *)Desc[i].ptr;
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->width, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->patlength, true);
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->color, true);
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->pattern, true);
+			break;
+		case typFILLDEF:
+			fd = (FillDEF *)Desc[i].ptr;
+			//we set the 'hatch' member to zero: reconstruct after read
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, fd->type, true, 0);
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fd->scale, true);
+			add_to_buff(&ptr, &cbOut, &sizeOut, " 0x0", 4);
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color2, true);
+			break;
+		case typGOBJ:
+			if(*(GraphObj **)(Desc[i].ptr)) add_int_to_buff(&ptr, &cbOut, &sizeOut, 
+				Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)), true, 0);
+			else cbOut = last;
+			break;
+		case typOBJLST:
+			if(!*(GraphObj ***)(Desc[i].ptr)){
+				cbOut = last;				break;
+				}
+			WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
+			break;
+		case typIPLST:
+			if(!*(POINT**)(Desc[i].ptr)){
+				cbOut = last;				break;
+				}
+			WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+			break;
+		case typFPLST:
+			if(!*(lfPOINT**)(Desc[i].ptr)){
+				cbOut = last;				break;
+				}
+			WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L, true);
+			break;
+		case typFPLST3D:
+			if(!*(fPOINT3D**)(Desc[i].ptr)){
+				cbOut = last;				break;
+				}
+			WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
+			break;
+		case typTEXT:
+			if(!*(char**)(Desc[i].ptr)) cbOut = last;
+			else WriteEscString(*((char**)Desc[i].ptr));
+			break;
+		case typTXTDEF:		case typPTRTXTDEF:
+			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
+			if(!tx) {
+				cbOut = last;				break;
+				}
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColTxt, true);
+			add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColBg, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->fSize, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotBL, true);
+			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotCHAR, true);
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Align, true, 0);
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Mode, true, 0);
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Style, true, 0);
+			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Font, true, 0);
+			if(tx->text && tx->text[0]) {
+				add_to_buff(&ptr, &cbOut, &sizeOut, " \"", 2);
+				add_to_buff(&ptr, &cbOut, &sizeOut, tx->text, 0);
+				add_to_buff(&ptr, &cbOut, &sizeOut, "\"\n", 2);
+				}
+			break;
+			}
+		if(Desc[i].type & typLAST) break;
+		}
+	if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+	return true;
+}
+
+void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
+{
+	int i, j, k, f[20];
+
+	if(!ptr || !first) return;
+#ifdef USE_WIN_SECURE
+	k = sscanf_s((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d", 
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+#else
+	k = sscanf((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d", 
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+#endif
+	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
+		ptr[i].x = f[j];	ptr[i].y = f[j+1];
+		}
+	while (i < count) {
+		if(!Cache->GetInt(&ptr[i].x) || !Cache->GetInt(&ptr[i].y)) return;
+		i++;
+		}
+}
+
+void ReadTypFpLst(lfPOINT *ptr, long count, unsigned char *first)
+{
+	double f[20];
+	int j, k;
+	long i;
+
+	if(!ptr || !first) return;
+#ifdef USE_WIN_SECURE
+	k = sscanf_s((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", 
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+#else
+	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", 
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+#endif
+	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
+		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];
+		}
+	while (i < count) {
+		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy)) return;
+		i++;
+		}
+}
+
+void ReadTypFpLst3D(fPOINT3D *ptr, long count, unsigned char *first)
+{
+	double f[21];
+	int j, k;
+	long i;
+
+	if(!ptr || !first) return;
+#ifdef USE_WIN_SECURE
+	k = sscanf_s((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
+#else
+	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
+		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
+#endif
+	for(i = 0,  j = 0; j < k && i < count; i++, j += 3) {
+		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];		ptr[i].fz = f[j+2];
+		}
+	while (i < count) {
+		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy) ||
+			!Cache->GetFloat(&ptr[i].fz)) return;
+		i++;
+		}
+}
+
+void TranslateEscChar(char *txt)
+{
+	int i, j;
+
+	if(txt && txt[0]) {
+		for(i = j = 0; txt[i]; i++) {
+			if(txt[i] == '\\') {
+				switch(txt[i+1]) {
+				case 'n':
+					txt[j++] = 0x0a;	i++;	break;
+				case 'r':
+					txt[j++] = 0x0d;	i++;	break;
+				case '"':	case 0x27:			case '\\':
+					txt[j++] = txt[++i];		break;
+				default:
+					txt[j++] = txt[i];	break;
+					}
+				}
+			else txt[j++] = txt[i];
+			}
+		txt[j] = 0;
+		}
+}
+
+void AddLines(char **txt)
+{
+	char tmp[1000], *ntxt;
+	bool mlines;
+	int i, j, cb = (int)strlen(*txt);
+
+	do {
+		mlines = false;
+		Cache->ReadLine(tmp, sizeof(tmp));
+		for(i = (int)strlen(tmp); i > 0 &&(tmp[i-1] < 33 || (tmp[i-1] == 
+			'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
+			(mlines = true))); tmp[--i] = 0);
+		for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
+		TranslateEscChar(tmp);
+		if(tmp[0] && (j = (int)strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
+			rlp_strcpy(ntxt+cb, j+1, tmp+i);
+			cb += j;	*(txt) = ntxt;
+			}
+		} while (mlines);
+}
+
+bool ExecInput(descIO *Desc)
+{
+	unsigned char c, tmp[1000], tmp2[20];
+	int i, j, k, l;
+	bool match, mlines;
+	int il, jl;
+	AxisDEF *ax;
+	POINT *lp;
+	lfPOINT *lfp;
+	fPOINT3D *lfp3d;
+	LineDEF *ld;
+	FillDEF *fd;
+	fRECT *fr;
+	GraphObj **gobs;
+	TextDEF *tx;
+
+	if(!Desc || !Desc[0].label) return false;
+	for(j = k = 0; ; ) {
+		do{
+			c = Cache->Getc();
+			switch (c) {
+			case '[':					//next object
+			case 0:						//probably eof
+				return true;
+			case '}':					//a lists hang over
+				c = Cache->Getc();
+				break;
+				}
+		} while(c <33);
+		for(i = 1, tmp[0] = c; i < sizeof(tmp) && '=' != (tmp[i] = Cache->Getc()); i++){
 			if(tmp[i] < 32 && tmp[i]) i = -1;			//some error conditions
-			else if(!tmp[i] && Cache->eof) return true;
-			else if(tmp[i] == '[') return true;
-			}
-		tmp[i] = 0;
-		match = mlines = false;
-		do {
-			if(0 == strcmp(tmp, Desc[j].label)) {
-				Cache->ReadLine(tmp, sizeof(tmp));
-				switch(Desc[j].type & 0xff){
-				case typNZINT:
-				case typINT:
-					sscanf(tmp, "%d", (int*)Desc[j].ptr);
-					break;
-				case typNZLFLOAT:
-				case typLFLOAT:
-					sscanf(tmp, "%lf", (double*)Desc[j].ptr);
-					break;
-				case typDWORD:
-					sscanf(tmp, "%x", (DWORD*)Desc[j].ptr);
-					break;
-				case typULONG:
-					sscanf(tmp, "%ld", (unsigned long*)Desc[j].ptr);
-					break;
-				case typFRECT:
-					fr = (fRECT*) Desc[j].ptr;
-					sscanf(tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
-					break;
-				case typNZLFPOINT:
-				case typLFPOINT:
-					lfp = (lfPOINT*) Desc[j].ptr;
-					sscanf(tmp, "%lf%lf", &lfp->fx, &lfp->fy);
-					break;
-				case typPOINT3D:
-					lfp3d = (fPOINT3D*) Desc[j].ptr;
-					sscanf(tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
-					break;
-				case typPTRAXDEF:
-				case typAXDEF:
-					ax = (Desc[j].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[j].ptr : *(AxisDEF **)Desc[j].ptr;
-					//pointer for typPTRAXDEF and memory allocated by the Axis module!
-					if(!ax) break;
-					sscanf(tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
-						&ax->loc[0].fx,	&ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
-						&ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx, 
-						&ax->Center.fy, &ax->Radius, &ax->nBreaks);
-					if(ax->nBreaks) {
-						ax->breaks = (lfPOINT*)calloc(ax->nBreaks, sizeof(lfPOINT));
-						for(i = 0; tmp[i] && tmp[i-1] != '{'; i++);
-						if(tmp[i]) {
-							ReadTypFpLst(ax->breaks, ax->nBreaks, (unsigned char*)tmp+i);
-							SortAxisBreaks(ax);
-							}
-						}
-					break;
-				case typLINEDEF:
-					ld = (LineDEF*) Desc[j].ptr;
-					sscanf(tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
-					break;
-				case typFILLDEF:
-					fd = (FillDEF*) Desc[j].ptr;
-					sscanf(tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
-					fd->hatch = 0L;
-					break;
-				case typGOBJ:
-					*(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol(tmp));
-					break;
-				case typOBJLST:
-					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
-					if(!tmp[i]) break;
-					if(sscanf(tmp+i+1, "%ld", &il) && il) {
-						*Desc[j].count = il;
-						if(!*(GraphObj***)(Desc[j].ptr)){
-							*(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
-							}
+			else if(!tmp[i] && Cache->eof) return true;
+			else if(tmp[i] == '[') return true;
+			}
+		tmp[i] = 0;
+		match = mlines = false;
+		do {
+			if(0 == strcmp((char*)tmp, Desc[j].label)) {
+				Cache->ReadLine((char*)tmp, sizeof(tmp));
+				switch(Desc[j].type & 0xff){
+				case typNZINT:
+				case typINT:
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%d", (int*)Desc[j].ptr);
+#else
+					sscanf((char*)tmp, "%d", (int*)Desc[j].ptr);
+#endif
+					break;
+				case typNZLFLOAT:		case typLFLOAT:
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%lf", (double*)Desc[j].ptr);
+#else
+					sscanf((char*)tmp, "%lf", (double*)Desc[j].ptr);
+#endif
+					break;
+				case typDWORD:
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
+#else
+					sscanf((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
+#endif
+					break;
+				case typFRECT:
+					fr = (fRECT*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
+#else
+					sscanf((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
+#endif
+					break;
+				case typNZLFPOINT:		case typLFPOINT:
+					lfp = (lfPOINT*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
+#else
+					sscanf((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
+#endif
+					break;
+				case typPOINT3D:
+					lfp3d = (fPOINT3D*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
+#else
+					sscanf((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
+#endif
+					break;
+				case typPTRAXDEF:
+				case typAXDEF:
+					ax = (Desc[j].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[j].ptr : *(AxisDEF **)Desc[j].ptr;
+					//pointer for typPTRAXDEF and memory allocated by the Axis module!
+					if(!ax) break;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
+						&ax->loc[0].fx,	&ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
+						&ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx, 
+						&ax->Center.fy, &ax->Radius, &ax->nBreaks);
+#else
+					sscanf((char*)tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
+						&ax->loc[0].fx,	&ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
+						&ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx, 
+						&ax->Center.fy, &ax->Radius, &ax->nBreaks);
+#endif
+					if(ax->nBreaks) {
+						ax->breaks = (lfPOINT*)calloc(ax->nBreaks, sizeof(lfPOINT));
+						for(i = 0; tmp[i] && tmp[i-1] != '{'; i++);
+						if(tmp[i]) {
+							ReadTypFpLst(ax->breaks, ax->nBreaks, (unsigned char*)tmp+i);
+							SortAxisBreaks(ax);
+							}
+						}
+					break;
+				case typLINEDEF:
+					ld = (LineDEF*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
+#else
+					sscanf((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
+#endif
+					break;
+				case typFILLDEF:
+					fd = (FillDEF*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
+#else
+					sscanf((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
+#endif
+					fd->hatch = 0L;
+					break;
+				case typGOBJ:
+					*(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol((char*)tmp));
+					break;
+				case typOBJLST:
+					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+					if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+					if(sscanf_s((char*)tmp+i+1, "%ld", &il) && il) {
+#else
+					if(sscanf((char*)tmp+i+1, "%ld", &il) && il) {
+#endif
+						*Desc[j].count = il;
+						if(!*(GraphObj***)(Desc[j].ptr)){
+							*(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
+							}
 						if((gobs = *(GraphObj***)(Desc[j].ptr))){
-							i += 4;
-							while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
-							strcat(tmp, " ");
-							for( ;il >0; il--) {
-								for(l = 0; l < sizeof(tmp2); ){
-									if(tmp[i]) c = tmp[i++];
-									else if(!(c = Cache->Getc())) break;
-									if(c >='0' && c <='9') tmp2[l++] = c;
-									else {
-										tmp2[l] = 0;
-										if(l)break;
-										}
-									}
-								sscanf(tmp2, "%ld", &jl);
-								*gobs++ = Notary->PopGO(jl);
-								if(c == '}') break;
-								}
-							}
-						}	
-					break;
-				case typIPLST:
-					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
-					if(!tmp[i]) break;
-					if(sscanf(tmp+i+1, "%ld", &il) && il) {
-						*Desc[j].count = il;
-						if(!*(POINT**)(Desc[j].ptr)){
-							*(POINT**)(Desc[j].ptr) = (POINT*)calloc(il, sizeof(POINT));
-							}
-						if(!(lp = *(POINT**)(Desc[j].ptr)))return false;
-						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
-						ReadTypIpLst(lp, il, (unsigned char*)tmp+i);
-						}
-					break;
-				case typFPLST:
-					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
-					if(!tmp[i]) break;
-					if(sscanf(tmp+i+1, "%ld", &il) && il) {
-						*Desc[j].count = il;
-						if(!*(lfPOINT**)(Desc[j].ptr)){
-							*(lfPOINT**)(Desc[j].ptr) = (lfPOINT*)calloc(il, sizeof(lfPOINT));
-							}
-						if(!(lfp = *(lfPOINT**)(Desc[j].ptr)))return false;
-						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
-						ReadTypFpLst(lfp, il, (unsigned char*)tmp+i);
-						}
-					break;
-				case typFPLST3D:
-					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
-					if(!tmp[i]) break;
-					if(sscanf(tmp+i+1, "%ld", &il) && il) {
-						*Desc[j].count = il;
-						if(!*(fPOINT3D**)(Desc[j].ptr)){
-							*(fPOINT3D**)(Desc[j].ptr) = (fPOINT3D*)calloc(il, sizeof(fPOINT3D));
-							}
-						if(!Desc[j].ptr)return false;
-						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
-						ReadTypFpLst3D(*(fPOINT3D**)(Desc[j].ptr), il, (unsigned char*)tmp+i);
-						}
-					break;
-				case typTEXT:
-					for(i = strlen(tmp); i > 0 &&(tmp[i-1] < 32 || (tmp[i-1] == 
-						'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
-						(mlines = true))); tmp[--i] = 0);
-					for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
-					TranslateEscChar(tmp);
-					if(tmp[0]){
-						*(char**)(Desc[j].ptr) = strdup(tmp+i);
-						if(mlines) AddLines((char**)(Desc[j].ptr));
-						}
-					break;
-				case typPTRTXTDEF:
-				case typTXTDEF:
-					tx = (Desc[j].type & 0xff) == typTXTDEF ? (TextDEF *)Desc[j].ptr : *(TextDEF **)Desc[j].ptr;
-					if(!tx) {
-						if((Desc[j].type & 0xff) == typTXTDEF) break;	//prabably wrong usage of typTXTDEF instad of
-																//    typPTRTXTDEF
-						tx = *(TextDEF **)(Desc[j].ptr) = (TextDEF*)calloc(1, sizeof(TextDEF));
-						if(!tx) return false;					//memory allocation error
-						}
-					sscanf(tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg, 
-						&tx->fSize, &tx->RotBL, &tx->RotCHAR,
-						&tx->Align, &tx->Mode, &tx->Style, &tx->Font);
-					tx->iSize = 0;
-					for(i = strlen(tmp); i >0 && tmp[i] != '"'; i--);
-					if(i) {
-						tmp[i] = 0;
-						for(l = 0; l <i && tmp[l] != '"'; l++);
-						if(i && tmp[l+1]) tx->text = strdup(tmp+l+1);
-						}
-					break;
-					}
-				match = true;			j++;	k++;
-				if(!Desc[j].label || (Desc[j-1].type & typLAST)) 
-					j = k = 0;	//rewind: items in file not sorted
-				}
-			else {
-				j++;
-				k++;
-				if(!Desc[j].label || (Desc[j-1].type & typLAST)) {				//Error:
-					if(k > j){						//  item not defined in Desc
-						match = true;				//  read parameters,
-						Cache->ReadLine(tmp, sizeof(tmp));	//   then continue
-						}
-					j= 0;
-					}
-				}
-			}while(!match);
-		}
-}
-
-bool SaveGraphAs(GraphObj *g)
-{
-	char *name = 0L;
+							i += 4;
+							while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+#ifdef USE_WIN_SECURE
+							strcat_s((char*)tmp, 1000, " ");
+#else
+							strcat((char*)tmp, " ");
+#endif
+							for( ;il >0; il--) {
+								for(l = 0; l < sizeof(tmp2); ){
+									if(tmp[i]) c = tmp[i++];
+									else if(!(c = Cache->Getc())) break;
+									if(c >='0' && c <='9') tmp2[l++] = c;
+									else {
+										tmp2[l] = 0;
+										if(l)break;
+										}
+									}
+#ifdef USE_WIN_SECURE
+								sscanf_s((char*)tmp2, "%d", &jl);
+#else
+								sscanf((char*)tmp2, "%d", &jl);
+#endif
+								*gobs++ = Notary->PopGO(jl);
+								if(c == '}') break;
+								}
+							}
+						}	
+					break;
+				case typIPLST:
+					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+					if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+						*Desc[j].count = il;
+						if(!*(POINT**)(Desc[j].ptr)){
+							*(POINT**)(Desc[j].ptr) = (POINT*)calloc(il, sizeof(POINT));
+							}
+						if(!(lp = *(POINT**)(Desc[j].ptr)))return false;
+						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+						ReadTypIpLst(lp, il, (unsigned char*)tmp+i);
+						}
+					break;
+				case typFPLST:
+					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+					if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+						*Desc[j].count = il;
+						if(!*(lfPOINT**)(Desc[j].ptr)){
+							*(lfPOINT**)(Desc[j].ptr) = (lfPOINT*)calloc(il, sizeof(lfPOINT));
+							}
+						if(!(lfp = *(lfPOINT**)(Desc[j].ptr)))return false;
+						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+						ReadTypFpLst(lfp, il, (unsigned char*)tmp+i);
+						}
+					break;
+				case typFPLST3D:
+					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+					if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+						*Desc[j].count = il;
+						if(!*(fPOINT3D**)(Desc[j].ptr)){
+							*(fPOINT3D**)(Desc[j].ptr) = (fPOINT3D*)calloc(il, sizeof(fPOINT3D));
+							}
+						if(!Desc[j].ptr)return false;
+						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+						ReadTypFpLst3D(*(fPOINT3D**)(Desc[j].ptr), il, (unsigned char*)tmp+i);
+						}
+					break;
+				case typTEXT:
+					for(i = (int)strlen((char*)tmp); i > 0 &&(tmp[i-1] < 32 || (tmp[i-1] == 
+						'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
+						(mlines = true))); tmp[--i] = 0);
+					for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
+					TranslateEscChar((char*)tmp);
+					if(tmp[0]){
+						*(char**)(Desc[j].ptr) = (char*)memdup((char*)tmp+i, (int)strlen((char*)tmp+i)+1, 0);
+						if(mlines) AddLines((char**)(Desc[j].ptr));
+						}
+					break;
+				case typPTRTXTDEF:
+				case typTXTDEF:
+					tx = (Desc[j].type & 0xff) == typTXTDEF ? (TextDEF *)Desc[j].ptr : *(TextDEF **)Desc[j].ptr;
+					if(!tx) {
+						if((Desc[j].type & 0xff) == typTXTDEF) break;	//prabably wrong usage of typTXTDEF instad of
+																//    typPTRTXTDEF
+						tx = *(TextDEF **)(Desc[j].ptr) = (TextDEF*)calloc(1, sizeof(TextDEF));
+						if(!tx) return false;					//memory allocation error
+						}
+#ifdef USE_WIN_SECURE
+					sscanf_s((char*)tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg, 
+						&tx->fSize, &tx->RotBL, &tx->RotCHAR,
+						&tx->Align, &tx->Mode, &tx->Style, &tx->Font);
+#else
+					sscanf((char*)tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg, 
+						&tx->fSize, &tx->RotBL, &tx->RotCHAR,
+						&tx->Align, &tx->Mode, &tx->Style, &tx->Font);
+#endif
+					tx->iSize = 0;
+					for(i = (int)strlen((char*)tmp); i >0 && tmp[i] != '"'; i--);
+					if(i) {
+						tmp[i] = 0;
+						for(l = 0; l <i && tmp[l] != '"'; l++);
+						if(i && tmp[l+1]) tx->text = (char*)memdup((char*)tmp+l+1, (int)strlen((char*)tmp+l+1)+1, 0);
+						}
+					break;
+					}
+				match = true;			j++;	k++;
+				if(!Desc[j].label || (Desc[j-1].type & typLAST)) 
+					j = k = 0;	//rewind: items in file not sorted
+				}
+			else {
+				j++;
+				k++;
+				if(!Desc[j].label || (Desc[j-1].type & typLAST)) {				//Error:
+					if(k > j){						//  item not defined in Desc
+						match = true;				//  read parameters,
+						Cache->ReadLine((char*)tmp, sizeof(tmp));	//   then continue
+						}
+					j= 0;
+					}
+				}
+			}while(!match);
+		}
+}
+
+bool SaveGraphAs(GraphObj *g)
+{
+	char *name = 0L;
 	int i;
-	bool bRet = true;
-
-	if(Notary || !g) {
-		ErrorBox("Output pending or\nno graph.");
-		return false;
-		}
-	cObsW = 0;
-	Notary = new notary();
-	if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
-		if(((Graph*)g)->filename) name = ((Graph*)g)->filename;
-		}
-	name = SaveGraphAsName(name);
-	if (name && Notary) {
-		iFile = OpenOutputFile(name);
-		if(iFile >=0) {
-			if(g && g->FileIO(FILE_WRITE)){
-				if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
-					g->Command(CMD_FILENAME, name, 0L);
-					}
-				for(i = strlen(name); i >=0 && name[i] != '/' && name[i] != '\\'; i--);
-				if(name[i]) i++;
-				g->Command(CMD_SETNAME, name+i, 0L);
-				g->Command(CMD_UPDHISTORY, 0L, 0L);
-				}
-			else ErrorBox("Could not write\ndata to file.");
-			}
-		else ErrorBox("Open failed for\noutput file.");
-		CloseOutputFile();
-		}
-	else bRet = false;
-	if(Notary) delete Notary;	Notary = 0L;
-	return bRet;
-}
-
-char *GraphToMem(GraphObj *g, long *size)
-{
+	bool bRet = true;
+
+	if(Notary || !g) {
+		ErrorBox("Output pending or\nno graph.");
+		return false;
+		}
+	cObsW = 0;
+	Notary = new notary();
+	if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
+		if(((Graph*)g)->filename) name = ((Graph*)g)->filename;
+		}
+	name = SaveGraphAsName(name);
+	if (name && Notary) {
+		iFile = OpenOutputFile(name);
+		if(iFile >=0) {
+			if(g && g->FileIO(FILE_WRITE)){
+				if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
+					g->Command(CMD_FILENAME, name, 0L);
+					}
+				for(i = (int)strlen(name); i >=0 && name[i] != '/' && name[i] != '\\'; i--);
+				if(name[i]) i++;
+				g->Command(CMD_SETNAME, name+i, 0L);
+				g->Command(CMD_UPDHISTORY, 0L, 0L);
+				}
+			else ErrorBox("Could not write\ndata to file.");
+			}
+		else ErrorBox("Open failed for\noutput file.");
+		CloseOutputFile();
+		}
+	else bRet = false;
+	if(Notary) delete Notary;	Notary = 0L;
+	return bRet;
+}
+
+char *GraphToMem(GraphObj *g, long *size)
+{
 	static char *ret;
-
-	if(Notary || !g) {
-		ErrorBox("Output pending or\nno graph.");
-		return false;
-		}
-	cObsW = 0;
-	iFile = cbOut = sizeOut = 0;	ptr = 0L;	ptr_step = 2048;
-	if (Notary = new notary()) {
+
+	if(Notary || !g) {
+		ErrorBox("Output pending or\nno graph.");
+		return false;
+		}
+	cObsW = 0;				iFile = -1;
+	cbOut = sizeOut = 0;	ptr = 0L;
+	if (Notary = new notary()) {
 		if(g && g->FileIO(FILE_WRITE)){
-			//all done
-			}
-		delete Notary;					Notary = 0L;
+			//all done
+			}
+		delete Notary;					Notary = 0L;
 		if(ptr) ptr[cbOut] = 0;
-		ret = ptr;						if(size) *size = cbOut;
-		iFile = cbOut = sizeOut = 0;	ptr = 0L;	ptr_step = 2048;
-		return ret;
-		}
-	return 0L;
-}
-
-void UpdGOfromMem(GraphObj *go, unsigned char *buff)
-{
-	int i=0;
-
-	if(!go || !buff) return;
-	iFile = cbOut = sizeOut = 0;	ptr = 0L;
-	for(i = 0; buff[i] && buff[i] != ']'; i++);
-	if(!buff[i])return;
-	for(; buff[i] && buff[i] <33; i++);
-	if(!buff[i] || i < 4) return;
-	if(!(Cache = new MemCache(buff+i-1))) return;
+		ret = ptr;						if(size) *size = cbOut;
+		iFile = -1;
+		cbOut = sizeOut = 0;	ptr = 0L;
+		return ret;
+		}
+	return 0L;
+}
+
+void UpdGOfromMem(GraphObj *go, unsigned char *buff)
+{
+	int i=0;
+
+	if(!go || !buff) return;
+	iFile = -1;							cbOut = sizeOut = 0;	ptr = 0L;
+	for(i = 0; buff[i] && buff[i] != ']'; i++);
+	if(!buff[i])return;
+	for(; buff[i] && buff[i] <33; i++);
+	if(!buff[i] || i < 4) return;
+	if(!(Cache = new MemCache(buff+i-1))) return;
 	if ((Notary = new notary()) && go->Id > GO_UNKNOWN && go->Id < GO_DEFRW) {
-		//notary not needed but saver if tree exists
-		go->Command(CMD_FLUSH, 0L, 0L);
-		go->FileIO(INIT_VARS);			go->FileIO(FILE_READ);
-		delete Notary;					Notary = 0L;
-		}
-	delete Cache;		Cache = 0L;
-}
-
-bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
-{
-	unsigned char c, tmp[80];
-	char debug[80];
-	unsigned long id, lid;
-	int i;
-	unsigned int hv;
-	GraphObj *go;
-
-	if(Notary || Cache) {
-		ErrorBox("Output pending:\nRead Error.");
-		return false;
-		}
-	if(!(Notary = new notary()))return false;
-	if(mem) {
-		if(!(Cache = new MemCache(mem))) return false;
-		}
-	else if(Cache = new ReadCache()){
-		if(!Cache->Open(name)) {
-			delete Notary;		delete Cache;
-			Notary = 0L;		Cache = 0L;
-			ErrorBox("Error open file");
-			return false;
-			}
-		}
-	else return false;
-	//DEBUG: skipping header
-	do {
-		c = Cache->Getc();
-		} while(c && c != '[');
-	if(!c) goto ReadErr;
-	do {
-		for(i = 0; i < sizeof(tmp) && c != '=' && c; i++){
+		//notary not needed but saver if tree exists
+		go->Command(CMD_FLUSH, 0L, 0L);
+		go->FileIO(INIT_VARS);			go->FileIO(FILE_READ);
+		delete Notary;					Notary = 0L;
+		}
+	delete Cache;		Cache = 0L;
+}
+
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
+{
+	unsigned char c, tmp[80];
+	char debug[80];
+	int i, id, lid;
+	unsigned int hv;
+	GraphObj *go;
+
+	LastOpenGO = 0L;
+	if(Notary || Cache) {
+		ErrorBox("Output pending:\nRead Error.");
+		return false;
+		}
+	if(!(Notary = new notary()))return false;
+	if(mem) {
+		if(!(Cache = new MemCache(mem))) return false;
+		}
+	else if(Cache = new ReadCache()){
+		if(!Cache->Open(name)) {
+			delete Notary;		delete Cache;
+			Notary = 0L;		Cache = 0L;
+			ErrorBox("Error open file");
+			return false;
+			}
+		}
+	else return false;
+	//DEBUG: skipping header
+	do {
+		c = Cache->Getc();
+		} while(c && c != '[');
+	if(!c) goto ReadErr;
+	do {
+		for(i = 0; i < sizeof(tmp) && c != '=' && c; i++){
 			tmp[i] = c = Cache->Getc();
 			if(c == '[') i = -1;
-			}
-		if(!c) goto ReadErr;
-		tmp[i] = tmp[i-1] = 0;			id=0;
-		sscanf((char*)tmp, "%ld", &id);
-		if(!id) goto ReadErr;
-		//go to class name
-		while((tmp[0] = Cache->Getc())<31 && tmp[0]);
-		if(!tmp[0]) goto ReadErr;
-		for(i = 1; i < sizeof(tmp) && c!= ']' && c; i++)
-			tmp[i] = c = Cache->Getc();
-		if(!c) goto ReadErr;
-		tmp[i-1] = 0;
-		go = 0L;
-		hv = HashValue(tmp);
-		switch(hv) {
-		case 3895:		go = new Axis(FILE_READ);			break;
-		case 886:		go = new Bar(FILE_READ);			break;
-		case 81384:		go = new Symbol(FILE_READ);			break;
-		case 62229:		go = new Bubble(FILE_READ);			break;
-		case 948:		go = new Box(FILE_READ);			break;
-		case 15411:		go = new Arrow(FILE_READ);			break;
-		case 1052406:	go = new ErrorBar(FILE_READ);		break;
-		case 324566:	go = new Whisker(FILE_READ);		break;
-		case 1031437:	go = new DropLine(FILE_READ);		break;
-		case 4839:		go = new Tick(FILE_READ);			break;
-		case 16832:		go = new Label(FILE_READ);			break;
-		case 1071373:	go = new GridLine(FILE_READ);		break;
-		case 963085:	go = new DataLine(FILE_READ);		break;
-		case 61662266:	go = new DataPolygon(FILE_READ);	break;
-		case 435228:	go = new segment(FILE_READ);		break;
-		case 1741325:	go = new polyline(FILE_READ);		break;
+			}
+		if(!c) goto ReadErr;
+		tmp[i] = tmp[i-1] = 0;			id=0;
+#ifdef USE_WIN_SECURE
+		sscanf_s((char*)tmp, "%d", &id);
+#else
+		sscanf((char*)tmp, "%d", &id);
+#endif
+		if(!id) goto ReadErr;
+		//go to class name
+		while((tmp[0] = Cache->Getc())<31 && tmp[0]);
+		if(!tmp[0]) goto ReadErr;
+		for(i = 1; i < sizeof(tmp) && c!= ']' && c; i++)
+			tmp[i] = c = Cache->Getc();
+		if(!c) goto ReadErr;
+		tmp[i-1] = 0;
+		go = 0L;
+		hv = HashValue(tmp);
+		switch(hv) {
+		case 3895:		go = new Axis(FILE_READ);			break;
+		case 886:		go = new Bar(FILE_READ);			break;
+		case 81384:		go = new Symbol(FILE_READ);			break;
+		case 62229:		go = new Bubble(FILE_READ);			break;
+		case 948:		go = new Box(FILE_READ);			break;
+		case 15411:		go = new Arrow(FILE_READ);			break;
+		case 1052406:	go = new ErrorBar(FILE_READ);		break;
+		case 324566:	go = new Whisker(FILE_READ);		break;
+		case 1031437:	go = new DropLine(FILE_READ);		break;
+		case 4839:		go = new Tick(FILE_READ);			break;
+		case 16832:		go = new Label(FILE_READ);			break;
+		case 1071373:	go = new GridLine(FILE_READ);		break;
+		case 963085:	go = new DataLine(FILE_READ);		break;
+		case 61662266:	go = new DataPolygon(FILE_READ);	break;
+		case 435228:	go = new segment(FILE_READ);		break;
+		case 1741325:	go = new polyline(FILE_READ);		break;
 		case 435258:	go = new polygon(FILE_READ);		break;
-		case 92534:		go = new Bezier(FILE_READ);			break;
-		case 6888037:	go = new rectangle(FILE_READ);		break;
-		case 1780087:	go = new roundrec(FILE_READ);		break;
-		case 78813:		go = new Sphere(FILE_READ);			break;
-		case 15463:		go = new Brick(FILE_READ);			break;
-		case 69952:		go = new Line3D(FILE_READ);			break;
-		case 386257:	go = new ellipse(FILE_READ);		break;
-		case 95680:		go = new mLabel(FILE_READ);			break;
-		case 4819316:	go = new PlotScatt(FILE_READ);		break;
+		case 92534:		go = new Bezier(FILE_READ);			break;
+		case 6888037:	go = new rectangle(FILE_READ);		break;
+		case 1780087:	go = new roundrec(FILE_READ);		break;
+		case 78813:		go = new Sphere(FILE_READ);			break;
+		case 15463:		go = new Brick(FILE_READ);			break;
+		case 69952:		go = new Line3D(FILE_READ);			break;
+		case 386257:	go = new ellipse(FILE_READ);		break;
+		case 95680:		go = new mLabel(FILE_READ);			break;
+		case 4819316:	go = new PlotScatt(FILE_READ);		break;
 		case 117848:	go = new xyStat(FILE_READ);			break;
-		case 15935312:	go = new BubblePlot(FILE_READ);		break;
-		case 247376:	go = new BoxPlot(FILE_READ);		break;
-		case 317384:	go = new StackBar(FILE_READ);		break;
-		case 1205932:	go = new PieChart(FILE_READ);		break;
-		case 16664:		go = new Graph(FILE_READ);			break;
-		case 25108:		go = new GoGroup(FILE_READ);		break;
-		case 300976:	go = new Scatt3D(FILE_READ);		break;
-		case 297280:	go = new Plane3D(FILE_READ);		break;
-		case 19227098:	go = new Regression(FILE_READ);		break;
-		case 297997:	go = new RegLine(FILE_READ);		break;
-		case 4318417:	go = new SDellipse(FILE_READ);		break;
-		case 4843600:	go = new PolarPlot(FILE_READ);		break;
-		case 977452:	go = new DensDisp(FILE_READ);		break;
-		case 4465:		go = new Page(FILE_READ);			break;
-		case 75120:		go = new Plot3D(FILE_READ);			break;
-		case 17142080:	go = new GridLine3D(FILE_READ);		break;
-		case 246688:	go = new Arrow3D(FILE_READ);		break;
-		case 75562:		go = new Ribbon(FILE_READ);			break;
-		case 16503104:	go = new DropLine3D(FILE_READ);		break;
-		case 28859579:	go = new svgOptions(FILE_READ);		break;
-		case 70259:		go = new Limits(FILE_READ);			break;
-		case 17145824:	go = new GridRadial(FILE_READ);		break;
-		case 1074714:	go = new Function(FILE_READ);		break;
-		case 256075:	go = new FitFunc(FILE_READ);		break;
-		case 273377:	go = new LegItem(FILE_READ);		break;
+		case 15935312:	go = new BubblePlot(FILE_READ);		break;
+		case 247376:	go = new BoxPlot(FILE_READ);		break;
+		case 317384:	go = new StackBar(FILE_READ);		break;
+		case 1205932:	go = new PieChart(FILE_READ);		break;
+		case 16664:		go = new Graph(FILE_READ);			break;
+		case 25108:		go = new GoGroup(FILE_READ);		break;
+		case 300976:	go = new Scatt3D(FILE_READ);		break;
+		case 297280:	go = new Plane3D(FILE_READ);		break;
+		case 19227098:	go = new Regression(FILE_READ);		break;
+		case 297997:	go = new RegLine(FILE_READ);		break;
+		case 4318417:	go = new SDellipse(FILE_READ);		break;
+		case 4843600:	go = new PolarPlot(FILE_READ);		break;
+		case 977452:	go = new DensDisp(FILE_READ);		break;
+		case 4465:		go = new Page(FILE_READ);			break;
+		case 75120:		go = new Plot3D(FILE_READ);			break;
+		case 17142080:	go = new GridLine3D(FILE_READ);		break;
+		case 246688:	go = new Arrow3D(FILE_READ);		break;
+		case 75562:		go = new Ribbon(FILE_READ);			break;
+		case 16503104:	go = new DropLine3D(FILE_READ);		break;
+		case 28859579:	go = new svgOptions(FILE_READ);		break;
+		case 70259:		go = new Limits(FILE_READ);			break;
+		case 17145824:	go = new GridRadial(FILE_READ);		break;
+		case 1074714:	go = new Function(FILE_READ);		break;
+		case 256075:	go = new FitFunc(FILE_READ);		break;
+		case 273377:	go = new LegItem(FILE_READ);		break;
 		case 1053744:	go = new FreqDist(FILE_READ);		break;
 		case 68748:		go = new Legend(FILE_READ);			break;
-		case 66800:		go = new Grid3D(FILE_READ);			break;
+		case 66800:		go = new Grid3D(FILE_READ);			break;
 		case 967843:	go = new DefsRW(FILE_READ);			break;
-		case 66848:		go = new Func3D(FILE_READ);			break;
-		default:
-			sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.",
-				id, tmp, hv);
-			InfoBox(debug);
-			}
-		if(go) {
-			if(((int)id) < 0) DeleteGO(go);		//temporary objects have id < 0
-			else if(!Notary->PushGO(lid = id, go)) DeleteGO(go);
-			}
-		if('[' != Cache->Lastc()) do {			//search next object
-			c = Cache->Getc();
-			} while(c && c != '[');
-		tmp[0] = 0;
-		}while (c);
-	Cache->Close();
-	if((go = Notary->PopGO(lid))) {
-		go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+		case 66848:		go = new Func3D(FILE_READ);			break;
+		case 5001225:	go = new TextFrame(FILE_READ);		break;
+		default:
+#ifdef USE_WIN_SECURE
+			sprintf_s(debug, 80, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
+#else
+			sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
+#endif
+			InfoBox(debug);
+			}
+		if(go) {
+			if(((int)id) < 0) DeleteGO(go);		//temporary objects have id < 0
+			else if(!Notary->PushGO(lid = id, go)) DeleteGO(go);
+			}
+		if('[' != Cache->Lastc()) do {			//search next object
+			c = Cache->Getc();
+			} while(c && c != '[');
+		tmp[0] = 0;
+		}while (c);
+	Cache->Close();
+	if((LastOpenGO = go = Notary->PopGO(lid))) {
+		go->Command(CMD_SET_DATAOBJ, 0L, 0L);
 		delete Notary;		Notary = 0L;
 		if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
 			// object accepted
@@ -941,1141 +1035,1204 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 		else if(go->Id >= GO_GRAPH 
 			&& !(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
 			DeleteGO(go);	go = 0L;
-			}
-		if(go) go->Command(CMD_FILENAME, name, 0L);
-		}
-	if(Notary) delete Notary;		Notary = 0L;
-	delete Cache;					Cache = 0L;
-	return true;
-
-ReadErr:
-	Cache->Close();
-	close(iFile);
-	delete Notary;
-	Notary = 0L;
-	delete Cache;
-	Cache = 0L;
-	if(!name || !defs.IniFile || strcmp(name, defs.IniFile))
-		ErrorBox("An error occured during read.");
-	return false;
-}
-
-bool InitVarsGO(descIO *Desc)
-{
-	int i;
-	AxisDEF *ax;
-	TextDEF *tx;
-
-	for(i = 0; Desc[i].label; i++) {
-		switch(Desc[i].type & 0xff) {
-		case typNZINT:
-		case typINT:
-			*(int*)Desc[i].ptr = 0;			
-			break;
-		case typNZLFLOAT:
-		case typLFLOAT:
-			*(double*)Desc[i].ptr = 0.0;
-			break;
-		case typDWORD:
-			*(DWORD*)Desc[i].ptr = 0x0L;
-			break;
-		case typULONG:
-			*(unsigned long*)Desc[i].ptr = 0L;
-			break;
-		case typFRECT:
-			((fRECT*)Desc[i].ptr)->Xmin = ((fRECT*)Desc[i].ptr)->Xmax =
-				((fRECT*)Desc[i].ptr)->Ymin = ((fRECT*)Desc[i].ptr)->Ymax = 0.0;
-			break;
-		case typNZLFPOINT:
-		case typLFPOINT:
-			((lfPOINT*)Desc[i].ptr)->fx = ((lfPOINT*)Desc[i].ptr)->fy = 0.0;
-			break;
-		case typPOINT3D:
-			((fPOINT3D*)Desc[i].ptr)->fx = ((fPOINT3D*)Desc[i].ptr)->fy =
-				((fPOINT3D*)Desc[i].ptr)->fz = 0.0;
-			break;
-		case typPTRAXDEF:
-		case typAXDEF:
-			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
-			if(!ax) break;
-			ax->owner = 0L;		ax->flags = 0L;		ax->breaks = 0L;	ax->nBreaks = 0;
-			ax->min = ax->max = ax->Start = ax->Step = 0.0f;
-			ax->loc[0].fx = ax->loc[0].fy = ax->loc[0].fz = 0.0f;
-			ax->loc[1].fx = ax->loc[1].fy = ax->loc[1].fz = 0.0f;
-			ax->Center.fx = ax->Center.fy = ax->Radius = 0.0f;
-			break;
-		case typLINEDEF:
-			((LineDEF*)Desc[i].ptr)->width = defs.GetSize(SIZE_HAIRLINE);
-			((LineDEF*)Desc[i].ptr)->patlength = defs.GetSize(SIZE_PATLENGTH);
-			((LineDEF*)Desc[i].ptr)->color = ((LineDEF*)Desc[i].ptr)->pattern = 0x0L;
-			break;
-		case typFILLDEF:
-			((FillDEF*)Desc[i].ptr)->type = FILL_NONE;
-			((FillDEF*)Desc[i].ptr)->color = 0x00ffffffL;
-			((FillDEF*)Desc[i].ptr)->scale = 1.0f;
-			((FillDEF*)Desc[i].ptr)->hatch = (LineDEF*)0L;
-			((FillDEF*)Desc[i].ptr)->color2 = 0x00ffffffL;
-			break;
-		case typGOBJ:
-			*(GraphObj **)Desc[i].ptr = (GraphObj*)0L;
-			break;
-		case typOBJLST:
-			*Desc[i].count = 0L;
-			*(GraphObj ***)Desc[i].ptr = (GraphObj**)0L;
-			break;
-		case typIPLST:
-			*Desc[i].count = 0L;
-			*(POINT **)Desc[i].ptr = (POINT*)0L;
-			break;
-		case typFPLST:
-			*Desc[i].count = 0L;
-			*(lfPOINT **)Desc[i].ptr = (lfPOINT*)0L;
-			break;
-		case typFPLST3D:
-			*Desc[i].count = 0L;
-			*(fPOINT3D **)Desc[i].ptr = (fPOINT3D*)0L;
-			break;
-		case typTEXT:
-			*(char **)Desc[i].ptr = (char*)0L;
-			break;
-		case typTXTDEF:
-			tx = (TextDEF *)Desc[i].ptr;
-			tx->ColTxt = 0x0L,			tx->ColBg = 0x00ffffffL;
-			tx->fSize = defs.GetSize(SIZE_TEXT);
-			tx->RotBL = tx->RotCHAR = 0.0;
-			tx->Align = tx->Mode = tx->Style = tx->Font = 0L;
-			tx->text = 0L;
-			break;
-		case typPTRTXTDEF:
-			*(TextDEF**)Desc[i].ptr = (TextDEF*)0L;
-			break;
-			}
-		if(Desc[i].type & typLAST) break;
-		}
-	return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Save object data to memory block
-static unsigned char *SavVarBuf = 0L;
-static long SavVarSize = 0,	SavVarPos = 0;
-void SavVarInit(long len)
-{
-	if(SavVarBuf) free(SavVarBuf);
-	SavVarBuf = (unsigned char *)malloc(SavVarSize = len+4096);
-	SavVarPos = 0;
-}
-
-bool SavVarAdd(void *ptr, int size)
-{
-	int len;
-
-	if(SavVarBuf) {
-		len = sizeof(unsigned char *) + sizeof(int) + size;
-		while (SavVarSize <= SavVarPos+len) {
-			if(!(SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarSize + 4096))) return false;
-			SavVarSize += 4096;
-			}
-		memcpy(SavVarBuf+SavVarPos, &ptr, sizeof(unsigned char *));
-		SavVarPos += sizeof(unsigned char *);
-		memcpy(SavVarBuf+SavVarPos, &size, sizeof(int));	SavVarPos += sizeof(int);
-		memcpy(SavVarBuf+SavVarPos, ptr, size);				SavVarPos += size;
-		return true;
-		}
-	return false;
-}
-
-void *SavVarFetch()
-{
-	void *tmp;
-
-	SavVarAdd(0L, 0);				
-	tmp = SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarPos);
-	SavVarSize = SavVarPos = 0;		SavVarBuf = 0L;
-	return tmp;
-}
-
-bool SaveVarGO(descIO *Desc)
-{
-	int i;
-	AxisDEF *ax;
-	TextDEF *tx;
-
-	for(i = 0; Desc[i].label; i++) {
-		switch(Desc[i].type & 0xff){
-		case typNZINT:
-		case typINT:
-			SavVarAdd(Desc[i].ptr, sizeof(int));
-			break;
-		case typNZLFLOAT:
-		case typLFLOAT:
-			SavVarAdd(Desc[i].ptr, sizeof(double));
-			break;
-		case typDWORD:
-			SavVarAdd(Desc[i].ptr, sizeof(DWORD));
-			break;
-		case typULONG:
-			SavVarAdd(Desc[i].ptr, sizeof(unsigned long));
-			break;
-		case typFRECT:
-			SavVarAdd(Desc[i].ptr, sizeof(fRECT));
-			break;
-		case typNZLFPOINT:
-		case typLFPOINT:
-			SavVarAdd(Desc[i].ptr, sizeof(lfPOINT));
-			break;
-		case typPOINT3D:
-			SavVarAdd(Desc[i].ptr, sizeof(fPOINT3D));
-			break;
-		case typAXDEF:
-		case typPTRAXDEF:
-			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
-			if(ax) {
-				SavVarAdd(ax, sizeof(AxisDEF));
-				if(ax->breaks && ax->nBreaks) {
-					SavVarAdd(ax->breaks, ax->nBreaks * sizeof(lfPOINT));
-					}
-				}
-			break;
-		case typLINEDEF:
-			SavVarAdd(Desc[i].ptr, sizeof(LineDEF));
-			break;
-		case typFILLDEF:
-			SavVarAdd(Desc[i].ptr, sizeof(FillDEF));
-			break;
-		case typGOBJ:	case typOBJLST:		//not supported
-			break;
-		case typIPLST:						//probably in the future
-			break;
-		case typFPLST:
-			break;
-		case typFPLST3D:
-			SavVarAdd(*((void **)Desc[i].ptr), sizeof(fPOINT3D) * (*Desc[i].count));
-			break;
-		case typTEXT:
-			if(*(char**)(Desc[i].ptr)) SavVarAdd(Desc[i].ptr, strlen(*(char**)(Desc[i].ptr))+1);
-			break;
-		case typTXTDEF:
-		case typPTRTXTDEF:
-			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
-			if(tx) SavVarAdd(tx, sizeof(TextDEF) - sizeof(char*));
-			break;
-			}
-		if(Desc[i].type & typLAST) break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Graphic object member funtions for IO
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-svgOptions::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"tagAttr", typTEXT, &svgattr, 0L},
-		{"Script", typLAST | typTEXT, &script, 0L}};
-
-	switch(rw) {
-	case INIT_VARS:
-		return InitVarsGO(Desc);
-	case FILE_READ:
-		return ExecInput(Desc);
-		}
-	return false;
-}
-
-bool
-Symbol::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"Idx", typINT, &idx, 0L},
-		{"Pos", typLFPOINT, &fPos, 0L},
-		{"Size", typLFLOAT, &size, 0L},
-		{"Line", typLINEDEF, &SymLine, 0L},
-		{"FillCol", typDWORD, &SymFill.color, 0L},
-		{"Text", typPTRTXTDEF, &SymTxt, 0L},
-		{"Name", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		size = parent ? parent->GetSize(SIZE_SYMBOL): defs.GetSize(SIZE_SYMBOL);
-		SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
-		SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : defs.GetSize(SIZE_SYM_LINE);
-		SymFill.type = FILL_NONE;
-		SymFill.color = parent ? parent->GetColor(COL_SYM_FILL) : defs.Color(COL_SYM_FILL);
-		SymFill.scale = 1.0f;
-		SymFill.hatch = (LineDEF *) 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		SymFill.hatch = (LineDEF *) 0L;
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Symbol", Desc);
-		}
-	return false;
-}
-
-
-bool
-Bubble::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"Pos", typLFPOINT, &fPos, 0L},
-		{"Size", typLFLOAT, &fs, 0L},
-		{"Line", typLINEDEF, &BubbleLine, 0L},
-		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
-		{"Fill", typFILLDEF, &BubbleFill, 0L},
-		{"Name", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		BubbleLine.width = defs.GetSize(SIZE_BUBBLE_LINE);
-		BubbleFillLine.width = defs.GetSize(SIZE_BUBBLE_HATCH_LINE);
-		BubbleLine.color = BubbleFillLine.color = defs.Color(COL_BUBBLE_LINE);
-		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
-		ssRef = 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		BubbleFill.hatch = &BubbleFillLine;
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Bubble", Desc);
-		}
-	return false;
-}
-
-bool
-Bar::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"Pos", typLFPOINT, &fPos, 0L},
-		{"Size", typLFLOAT, &size, 0L},
-		{"Org", typLFPOINT, &BarBase, 0L},
-		{"Line", typLINEDEF, &BarLine, 0L},
-		{"Fill", typFILLDEF, &BarFill, 0L},
-		{"FillLine", typLINEDEF, &HatchLine, 0L},
-		{"Name", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		type = BAR_VERTB;
-		memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
-		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
-		BarFill.hatch = &HatchLine;
-		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
-		size = parent ? parent->GetSize(SIZE_BAR): defs.GetSize(SIZE_BAR);
-		mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		BarFill.hatch = &HatchLine;
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Bar", Desc);
-		}
-	return false;
-}
-
-void
-DataLine::FileValues(char *name, int type, double start, double step)
-{
-	FILE *file;
-	int i, c;
-	double fx;
-	lfPOINT *tfp;
-
-	if(!(file = fopen(name, "r"))) {
-		sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
-		ErrorBox(TmpTxt);
-		return;
-		}
-	if(Values) free(Values);
-	if(!(Values = (lfPOINT*)calloc( nPnt = 1000, sizeof(lfPOINT)))){
-		fclose(file);
-		return;
-		}
-	switch(type) {
-	case 1:				//x and y values
-		i = 0;
-		do {
-			c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
-			i++;
-			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
-				Values = tfp;			nPnt += 1000;
-				}
-			else if(i >= nPnt) break;
-			}while(c == 2);
-		i--;
-		break;
-	case 2:				//only y values
-		i = 0;	fx = start;
-		do {
-			c = fscanf(file, "%lf", &Values[i].fy);
-			Values[i].fx = fx;
-			i++;	fx += step;
-			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
-				Values = tfp;			nPnt += 1000;
-				}
-			}while(c == 1);
-		i--;
-		break;
-		}
-	nPntSet = i-1;
-	fclose(file);
-}
-
-bool
-DataLine::FileIO(int rw)
-{
-	long i;
-	char *file1 = 0L;
-	char *file2 = 0L;
-	double Start = 0.0f, Step = 0.0f;
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssXref", typTEXT, &ssXref, 0L},
-		{"ssYref", typTEXT, &ssYref, 0L},
-		{"BgCol", typDWORD, &BgColor, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"Data", typFPLST, &Values, &i},
-		{"file_xy", typTEXT, &file2, 0L},
-		{"start_x", typNZLFLOAT, &Start, 0L},
-		{"step_x", typNZLFLOAT, &Step, 0L},
-		{"file_y", typLAST | typTEXT, &file1, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		isPolygon = false;
-		nPnt = nPntSet = cp = 0;
-		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
-		BgColor = defs.Color(COL_BG);
-		pts = 0L;		dirty = true;	mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		min.fx = min.fy = max.fx = max.fy = 0.0;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		nPnt = i;
-		nPntSet = i-1;
-		if(file2)FileValues(file2, 1, 0.0, 1.0);
-		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
-		if(file1) free(file1);
-		if(file2) free(file2);
-		if(i && Values)return true;
-		break;
-	case FILE_WRITE:
-		i = nPntSet+1;
-		return ExecOutput(Notary->RegisterGO(this), "DataLine", Desc);
-		}
-	return false;
-}
-
-bool
-DataPolygon::FileIO(int rw)
-{
-	long i;
-	char *file1 = 0L;
-	char *file2 = 0L;
-	double Start = 0.0f, Step = 0.0f;
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssXref", typTEXT, &ssXref, 0L},
-		{"ssYref", typTEXT, &ssYref, 0L},
-		{"BgCol", typDWORD, &BgColor, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"FillLine", typLINEDEF, &pgFillLine, 0L},
-		{"Fill", typFILLDEF, &pgFill, 0L},
-		{"Data", typFPLST, &Values, &i},
-		{"file_xy", typTEXT, &file2, 0L},
-		{"start_x", typNZLFLOAT, &Start, 0L},
-		{"step_x", typNZLFLOAT, &Step, 0L},
-		{"file_y", typLAST | typTEXT, &file1, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		isPolygon = true;
-		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
-		LineDef.pattern = 0L;
-		BgColor = defs.Color(COL_BG);
-		memcpy(&pgFill, defs.GetFill(), sizeof(FillDEF));
-		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
-		pgFill.hatch = &pgFillLine;		dirty = true;	mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		min.fx = min.fy = max.fx = max.fy = 0.0f;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		nPnt = i;
-		nPntSet = i-1;
-		if(file2)FileValues(file2, 1, 0.0f, 1.0f);
-		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
-		if(file1) free(file1);
-		if(file2) free(file2);
-		pgFill.hatch = &pgFillLine;
-		if(i && Values)return true;
-		break;
-	case FILE_WRITE:
-		i = nPntSet+1;
-		return ExecOutput(Notary->RegisterGO(this), "DataPolygon", Desc);
-		}
-	return false;
-}
-
-bool
-RegLine::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"type", typNZINT, &type, 0L},
-		{"nPoints", typINT, &nPoints, 0L},
-		{"BgCol", typDWORD, &BgColor, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"Range", typFRECT, &lim, 0L},
-		{"uClip", typFRECT, &uclip, 0L},
-		{"mx", typNZLFLOAT, &mx, 0L},
-		{"my", typNZLFLOAT, &my, 0L},
-		{"li1", typLFPOINT, &l1, 0L},
-		{"li2", typLFPOINT, &l2, 0L},
-		{"li3", typLFPOINT, &l3, 0L},
-		{"li4", typLFPOINT, &l4, 0L},
-		{"li5", typLAST | typLFPOINT, &l5, 0L}};
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		cp = 0;
-		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
-		BgColor = defs.Color(COL_BG);
-		pts = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "RegLine", Desc);
-		}
-	return false;
-}
+			}
+		if(go) go->Command(CMD_FILENAME, name, 0L);
+		}
+	if(Notary) delete Notary;		Notary = 0L;
+	delete Cache;					Cache = 0L;
+	return true;
 
-void
-SDellipse::RegGO(void *n)
+ReadErr:
+	Cache->Close();	
+#ifdef USE_WIN_SECURE
+	if(iFile >= 0) _close(iFile);
+#else
+	if(iFile >= 0) close(iFile);
+#endif
+	iFile = -1;
+	delete Notary;		Notary = 0L;
+	delete Cache;		Cache = 0L;
+	if(!name || !defs.IniFile || strcmp(name, defs.IniFile))
+		ErrorBox("An error occured during read.");
+	return false;
+}
+
+bool InitVarsGO(descIO *Desc)
 {
-	if(n) {
-		if(rl)rl->RegGO(n);
-		((notary*)n)->AddRegGO(this);
-	}
+	int i;
+	AxisDEF *ax;
+	TextDEF *tx;
+
+	for(i = 0; Desc[i].label; i++) {
+		switch(Desc[i].type & 0xff) {
+		case typNZINT:
+		case typINT:
+			*(int*)Desc[i].ptr = 0;			
+			break;
+		case typNZLFLOAT:
+		case typLFLOAT:
+			*(double*)Desc[i].ptr = 0.0;
+			break;
+		case typDWORD:
+			*(DWORD*)Desc[i].ptr = 0x0L;
+			break;
+		case typFRECT:
+			((fRECT*)Desc[i].ptr)->Xmin = ((fRECT*)Desc[i].ptr)->Xmax =
+				((fRECT*)Desc[i].ptr)->Ymin = ((fRECT*)Desc[i].ptr)->Ymax = 0.0;
+			break;
+		case typNZLFPOINT:
+		case typLFPOINT:
+			((lfPOINT*)Desc[i].ptr)->fx = ((lfPOINT*)Desc[i].ptr)->fy = 0.0;
+			break;
+		case typPOINT3D:
+			((fPOINT3D*)Desc[i].ptr)->fx = ((fPOINT3D*)Desc[i].ptr)->fy =
+				((fPOINT3D*)Desc[i].ptr)->fz = 0.0;
+			break;
+		case typPTRAXDEF:
+		case typAXDEF:
+			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+			if(!ax) break;
+			ax->owner = 0L;		ax->flags = 0L;		ax->breaks = 0L;	ax->nBreaks = 0;
+			ax->min = ax->max = ax->Start = ax->Step = 0.0f;
+			ax->loc[0].fx = ax->loc[0].fy = ax->loc[0].fz = 0.0f;
+			ax->loc[1].fx = ax->loc[1].fy = ax->loc[1].fz = 0.0f;
+			ax->Center.fx = ax->Center.fy = ax->Radius = 0.0f;
+			break;
+		case typLINEDEF:
+			((LineDEF*)Desc[i].ptr)->width = defs.GetSize(SIZE_HAIRLINE);
+			((LineDEF*)Desc[i].ptr)->patlength = defs.GetSize(SIZE_PATLENGTH);
+			((LineDEF*)Desc[i].ptr)->color = ((LineDEF*)Desc[i].ptr)->pattern = 0x0L;
+			break;
+		case typFILLDEF:
+			((FillDEF*)Desc[i].ptr)->type = FILL_NONE;
+			((FillDEF*)Desc[i].ptr)->color = 0x00ffffffL;
+			((FillDEF*)Desc[i].ptr)->scale = 1.0f;
+			((FillDEF*)Desc[i].ptr)->hatch = (LineDEF*)0L;
+			((FillDEF*)Desc[i].ptr)->color2 = 0x00ffffffL;
+			break;
+		case typGOBJ:
+			*(GraphObj **)Desc[i].ptr = (GraphObj*)0L;
+			break;
+		case typOBJLST:
+			*Desc[i].count = 0L;
+			*(GraphObj ***)Desc[i].ptr = (GraphObj**)0L;
+			break;
+		case typIPLST:
+			*Desc[i].count = 0L;
+			*(POINT **)Desc[i].ptr = (POINT*)0L;
+			break;
+		case typFPLST:
+			*Desc[i].count = 0L;
+			*(lfPOINT **)Desc[i].ptr = (lfPOINT*)0L;
+			break;
+		case typFPLST3D:
+			*Desc[i].count = 0L;
+			*(fPOINT3D **)Desc[i].ptr = (fPOINT3D*)0L;
+			break;
+		case typTEXT:
+			*(char **)Desc[i].ptr = (char*)0L;
+			break;
+		case typTXTDEF:
+			tx = (TextDEF *)Desc[i].ptr;
+			tx->ColTxt = 0x0L,			tx->ColBg = 0x00ffffffL;
+			tx->fSize = defs.GetSize(SIZE_TEXT);
+			tx->RotBL = tx->RotCHAR = 0.0;
+			tx->Align = tx->Mode = tx->Style = tx->Font = 0L;
+			tx->text = 0L;
+			break;
+		case typPTRTXTDEF:
+			*(TextDEF**)Desc[i].ptr = (TextDEF*)0L;
+			break;
+			}
+		if(Desc[i].type & typLAST) break;
+		}
+	return true;
 }
 
-bool
-SDellipse::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"type", typNZINT, &type, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"Range", typFRECT, &lim, 0L},
-		{"Regr", typGOBJ, &rl, 0L},
-		{"Data", typLAST | typFPLST, &val, &nPoints}};
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		memcpy(&LineDef, defs.GetOutLine(), sizeof(LineDEF));
-		pts = 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		if(rl) rl->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(rl) rl->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "SDellipse", Desc);
-		}
-	return false;
-}
-
-bool
-ErrorBar::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"Pos", typLFPOINT, &fPos, 0L},
-		{"Err", typLFLOAT, &ferr, 0L},
-		{"Size", typLFLOAT, &SizeBar, 0L},
-		{"Line", typLINEDEF, &ErrLine, 0L},
-		{"Desc", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		SizeBar = defs.GetSize(SIZE_ERRBAR);
-		ErrLine.width = defs.GetSize(SIZE_ERRBAR_LINE);
-		ErrLine.color = defs.Color(COL_SYM_LINE);
-		mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "ErrorBar", Desc);
-		}
-	return false;
-}
-
-bool
-Arrow::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"moveable", typNZINT, &moveable, 0L},
-		{"p1", typLFPOINT, &pos1, 0L},
-		{"p2", typLFPOINT, &pos2, 0L},
-		{"CapW", typLFLOAT, &cw, 0L},
-		{"CapL", typLFLOAT, &cl, 0L},
-		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		cw = defs.GetSize(SIZE_ARROW_CAPWIDTH);
-		cl = defs.GetSize(SIZE_ARROW_CAPLENGTH);
-		LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
-		LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : defs.GetSize(SIZE_ARROW_LINE);
-		type = ARROW_LINE;
-		dh1 = dh2 = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Arrow", Desc);
-		}
-	return false;
-}
-
-bool
-Box::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"High", typLFPOINT, &pos1, 0L},
-		{"Low", typLFPOINT, &pos2, 0L},
-		{"Size", typLFLOAT, &size, 0L},
-		{"Line", typLINEDEF, &Outline, 0L},
-		{"FillLine", typLINEDEF, &Hatchline, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"Name", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		memcpy(&Outline, defs.GetOutLine(), sizeof(LineDEF));
-		memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
-		if(Fill.hatch)memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
-		Fill.hatch = &Hatchline;
-		size = defs.GetSize(SIZE_BAR);
-		ssRef = 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		Fill.hatch = &Hatchline;
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Box", Desc);
-		}
-	return false;
-}
-
-bool
-Whisker::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"High", typLFPOINT, &pos1, 0L},
-		{"Low", typLFPOINT, &pos2, 0L},
-		{"Size", typLFLOAT, &size, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"Desc", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		size = defs.GetSize(SIZE_WHISKER);
-		LineDef.width = defs.GetSize(SIZE_WHISKER_LINE);
-		LineDef.color = defs.Color(COL_WHISKER);
-		mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Whisker", Desc);
-		}
-	return false;
-}
-
-bool
-DropLine::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typINT, &type, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"Pos", typLFPOINT, &fPos, 0L},
-		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		LineDef.color = defs.Color(COL_SYM_LINE);
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "DropLine", Desc);
-		}
-	return false;
-}
-
-bool
-Sphere::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"Pos", typPOINT3D, &fPos, 0L},
-		{"Size", typLFLOAT, &size, 0L},
-		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		size = defs.GetSize(SIZE_SYMBOL);
-		Line.color = defs.Color(COL_SYM_LINE);
-		Line.width = defs.GetSize(SIZE_SYM_LINE);
-		Fill.color = defs.Color(COL_SYM_FILL);
-		scl = 0L;		nscl = 0;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Sphere", Desc);
-		}
-	return false;
-}
-
-bool
-Plane3D::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"values", typLAST | typFPLST3D, &dt, &ndt}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		ipl = 0L;	pts = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Plane3D", Desc);
-		}
-	return false;
-}
-
-bool
-Brick::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"Pos", typPOINT3D, &fPos, 0L},
-		{"depth", typLFLOAT, &depth, 0L},
-		{"width", typLFLOAT, &width, 0L},
-		{"height", typLFLOAT, &height, 0L},
-		{"flags", typDWORD, &flags, 0L},
-		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		Line.color = defs.Color(COL_SYM_LINE);
-		Line.width = defs.GetSize(SIZE_SYM_LINE);
-		Fill.color = defs.Color(COL_SYM_FILL);
-		faces = (plane**)calloc(6, sizeof(plane*));
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		mo = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Brick", Desc);
-		}
-	return false;
-}
-
-bool
-DropLine3D::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typINT, &type, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Pos", typPOINT3D, &fPos, 0L},
-		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		Line.color = defs.Color(COL_SYM_LINE);
-		Line.width = defs.GetSize(SIZE_HAIRLINE);	mo = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		ls[0] = ls[1] = ls[2] = ls[3] = ls[4] = ls[5] = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "DropLine3D", Desc);
-		}
-	return false;
-}
-
-bool
-Arrow3D::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typINT, &type, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Org", typPOINT3D, &fPos1, 0L},
-		{"Pos", typPOINT3D, &fPos2, 0L},
-		{"CapW", typLFLOAT, &cw, 0L},
-		{"CapL", typLFLOAT, &cl, 0L},
-		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		cw = defs.GetSize(SIZE_ARROW_CAPWIDTH);
-		cl = defs.GetSize(SIZE_ARROW_CAPLENGTH);
-		Line.color = defs.Color(COL_ARROW);
-		Line.width = defs.GetSize(SIZE_ARROW_LINE);
-		ls[0] = ls[1] = ls[2] = 0L;
-		cap = 0L;
-		type = ARROW_LINE;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Arrow3D", Desc);
-		}
-	return false;
-}
-
-bool
-Line3D::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Line", typLINEDEF, &Line, 0L},
-		{"ssRefX", typTEXT, &x_range, 0L},
-		{"ssRefY", typTEXT, &y_range, 0L},
-		{"ssRefZ", typTEXT, &z_range, 0L},
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"values", typLAST | typFPLST3D, &values, &nPts}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		Line.color = defs.Color(COL_DATA_LINE);
-		Line.width = defs.GetSize(SIZE_DATA_LINE);
-		ls = 0L;	pts = 0L;	npts = 0L;	mo=0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		min.fx = min.fy = min.fz = max.fx = max.fy = max.fz = 0.0;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		if(nPts > 1) ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Line3D", Desc);
-		}
-	return false;
-}
-
-bool
-Label::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"ssRef", typIPLST, &ssRef, &cssRef},
-		{"moveable", typNZINT, &moveable, 0L},
-		{"Pos", typNZLFPOINT, &fPos, 0L},
-		{"Dist", typNZLFPOINT, &fDist, 0L},
-		{"Flags", typDWORD, &flags, 0L},
-		{"TxtDef", typLAST | typTXTDEF, &TextDef, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		TextDef.ColTxt = 0x0L;
-		TextDef.ColBg = 0x00ffffffL;
-		TextDef.fSize = defs.GetSize(SIZE_TEXT);
-		TextDef.RotBL = TextDef.RotCHAR = 0.0;
-		TextDef.iSize = 0;
-		TextDef.Align = TXA_VTOP | TXA_HLEFT;
-		TextDef.Mode = TXM_TRANSPARENT;
-		TextDef.Style = TXS_NORMAL;
-		TextDef.Font = FONT_HELVETICA;
-		TextDef.text = 0L;	bgcolor = 0x00ffffffL;
-		bgLine.width = 0.0;		bgLine.patlength = 6.0;
-		bgLine.color = bgcolor;	bgLine.pattern = 0L;
-		CursorPos = 0;	defDisp = 0L;	bBGvalid = bModified = false;
-		curr_z = 0.0;		is3D = false;	fmt_txt = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Label", Desc);
-		}
-	return false;
-}
-
-void
-mLabel::RegGO(void *n)
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Save object data to memory block
+static unsigned char *SavVarBuf = 0L;
+static long SavVarSize = 0,	SavVarPos = 0;
+void SavVarInit(long len)
+{
+	if(SavVarBuf) free(SavVarBuf);
+	SavVarBuf = (unsigned char *)malloc(SavVarSize = len+4096);
+	SavVarPos = 0;
+}
+
+bool SavVarAdd(void *ptr, int size)
+{
+	int len;
+
+	if(SavVarBuf) {
+		len = sizeof(unsigned char *) + sizeof(int) + size;
+		while (SavVarSize <= SavVarPos+len) {
+			if(!(SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarSize + 4096))) return false;
+			SavVarSize += 4096;
+			}
+		memcpy(SavVarBuf+SavVarPos, &ptr, sizeof(unsigned char *));
+		SavVarPos += sizeof(unsigned char *);
+		memcpy(SavVarBuf+SavVarPos, &size, sizeof(int));	SavVarPos += sizeof(int);
+		memcpy(SavVarBuf+SavVarPos, ptr, size);				SavVarPos += size;
+		return true;
+		}
+	return false;
+}
+
+void *SavVarFetch()
+{
+	void *tmp;
+
+	SavVarAdd(0L, 0);				
+	tmp = SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarPos);
+	SavVarSize = SavVarPos = 0;		SavVarBuf = 0L;
+	return tmp;
+}
+
+bool SaveVarGO(descIO *Desc)
 {
 	int i;
+	AxisDEF *ax;
+	TextDEF *tx;
 
-	if(n) {
-		if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]) Lines[i]->RegGO(n);
-		((notary*)n)->AddRegGO(this);
-	}
+	for(i = 0; Desc[i].label; i++) {
+		switch(Desc[i].type & 0xff){
+		case typNZINT:
+		case typINT:
+			SavVarAdd(Desc[i].ptr, sizeof(int));
+			break;
+		case typNZLFLOAT:
+		case typLFLOAT:
+			SavVarAdd(Desc[i].ptr, sizeof(double));
+			break;
+		case typDWORD:
+			SavVarAdd(Desc[i].ptr, sizeof(DWORD));
+			break;
+		case typFRECT:
+			SavVarAdd(Desc[i].ptr, sizeof(fRECT));
+			break;
+		case typNZLFPOINT:
+		case typLFPOINT:
+			SavVarAdd(Desc[i].ptr, sizeof(lfPOINT));
+			break;
+		case typPOINT3D:
+			SavVarAdd(Desc[i].ptr, sizeof(fPOINT3D));
+			break;
+		case typAXDEF:
+		case typPTRAXDEF:
+			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+			if(ax) {
+				SavVarAdd(ax, sizeof(AxisDEF));
+				if(ax->breaks && ax->nBreaks) {
+					SavVarAdd(ax->breaks, ax->nBreaks * sizeof(lfPOINT));
+					}
+				}
+			break;
+		case typLINEDEF:
+			SavVarAdd(Desc[i].ptr, sizeof(LineDEF));
+			break;
+		case typFILLDEF:
+			SavVarAdd(Desc[i].ptr, sizeof(FillDEF));
+			break;
+		case typGOBJ:	case typOBJLST:		//not supported
+			break;
+		case typIPLST:						//probably in the future
+			break;
+		case typFPLST:
+			break;
+		case typFPLST3D:
+			SavVarAdd(*((void **)Desc[i].ptr), sizeof(fPOINT3D) * (*Desc[i].count));
+			break;
+		case typTEXT:
+			if(*(char**)(Desc[i].ptr)) SavVarAdd(Desc[i].ptr, (int)strlen(*(char**)(Desc[i].ptr))+1);
+			break;
+		case typTXTDEF:
+		case typPTRTXTDEF:
+			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
+			if(tx) SavVarAdd(tx, sizeof(TextDEF) - sizeof(char*));
+			break;
+			}
+		if(Desc[i].type & typLAST) break;
+		}
+	return false;
 }
-
-bool
-mLabel::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"moveable", typNZINT, &moveable, 0L},
-		{"Pos", typNZLFPOINT, &fPos, 0L},
-		{"Dist", typNZLFPOINT, &fDist, 0L},
-		{"lspc", typLFLOAT, &lspc, 0L},
-		{"Flags", typDWORD, &flags, 0L},
-		{"TxtDef", typTXTDEF, &TextDef, 0L},
-		{"Lines", typLAST | typOBJLST, &Lines, &nLines}};
-	int i;
-
-	switch(rw) {
-	case SAVE_VARS:
-		//The lines inherit settings from this object.
-		//We need not save them in this context
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		TextDef.ColTxt = 0x0L;
-		TextDef.ColBg = 0x00ffffffL;
-		TextDef.fSize = defs.GetSize(SIZE_TEXT);
-		TextDef.RotBL = TextDef.RotCHAR = 0.0;
-		TextDef.iSize = 0;
-		TextDef.Align = TXA_VTOP | TXA_HLEFT;
-		TextDef.Mode = TXM_TRANSPARENT;
-		TextDef.Style = TXS_NORMAL;
-		TextDef.Font = FONT_HELVETICA;
-		TextDef.text = 0L;
-		undo_flags = 0L;	lspc = 1.0;
-		curr_z = 0.0;		is3D = false;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		if(Lines) for ( i = 0; i < nLines; i++)
-			if(Lines[i]) Lines[i]->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(Lines) for ( i = 0; i < nLines; i++)
-			if(Lines[i]) Lines[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "mLabel", Desc);
-		}
-	return false;
-}
-
-bool
-segment::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"moveable", typNZINT, &moveable, 0L},
-		{"cent", typLFPOINT, &fCent, 0L},
-		{"ri", typNZLFLOAT, &radius1, 0L},
-		{"ra", typLFLOAT, &radius2, 0L},
-		{"start", typLFLOAT, &angle1, 0L},
-		{"end", typLFLOAT, &angle2, 0L},
-		{"shout", typNZLFLOAT, &shift, 0L},
-		{"Line", typLINEDEF, &segLine, 0L},
-		{"FillLine", typLINEDEF, &segFillLine, 0L},
-		{"Fill", typLAST | typFILLDEF, &segFill, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		segLine.width = defs.GetSize(SIZE_SEGLINE);
-		pts = 0L;	nPts = 0;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		segFill.hatch = &segFillLine;
-		return true;
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "segment", Desc);
-		}
-	return false;
-}
-
-bool
-polyline::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"moveable", typNZINT, &moveable, 0L},
-		{"Data", typFPLST, &Values, &nPoints},
-		{"Line", typLINEDEF, &pgLine, 0L},
-		{"FillLine", typLINEDEF, &pgFillLine, 0L},
-		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
-	
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		memcpy(&pgLine, defs.plLineDEF(0L), sizeof(LineDEF));
-		memcpy(&pgFill, defs.pgFillDEF(0L), sizeof(FillDEF));
-		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
-		pgFill.hatch = &pgFillLine;
-		pts = 0L;		nPts = 0;
-		pHandles = 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		pgFill.hatch = &pgFillLine;
-		return true;
-	case FILE_WRITE:
-		if(type != 1) Desc[3].type |= typLAST;	//skip fill for polyline
-		return ExecOutput(Notary->RegisterGO(this), 
-			type == 1 ? (char*)"polygon" : (char*)"polyline", Desc);
-		}
-	return false;
-}
-
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphic object member funtions for IO
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool
-Bezier::FileIO(int rw)
+svgOptions::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"tagAttr", typTEXT, &svgattr, 0L},
+		{"Script", typLAST | typTEXT, &script, 0L}};
+
+	switch(rw) {
+	case INIT_VARS:
+		return InitVarsGO(Desc);
+	case FILE_READ:
+		return ExecInput(Desc);
+		}
+	return false;
+}
+
+bool
+Symbol::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
-		{"moveable", typNZINT, &moveable, 0L},
-		{"Data", typFPLST, &Values, &nPoints},
-		{"Line", typLINEDEF, &pgLine, 0L},
-		{"FillLine", typLINEDEF, &pgFillLine, 0L},
-		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
-	
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"Idx", typINT, &idx, 0L},
+		{"Pos", typLFPOINT, &fPos, 0L},
+		{"Size", typLFLOAT, &size, 0L},
+		{"Line", typLINEDEF, &SymLine, 0L},
+		{"FillCol", typDWORD, &SymFill.color, 0L},
+		{"Text", typPTRTXTDEF, &SymTxt, 0L},
+		{"Name", typLAST | typTEXT, &name, 0L}};
+
 	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
 	case INIT_VARS:
-		//assume that all initialization is done by polyline::FileIO(int rw)
+		InitVarsGO(Desc);
+		size = DefSize(SIZE_SYMBOL);
+		SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
+		SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : DefSize(SIZE_SYM_LINE);
+		SymFill.type = FILL_NONE;
+		SymFill.color = parent ? parent->GetColor(COL_SYM_FILL) : defs.Color(COL_SYM_FILL);
+		SymFill.scale = 1.0f;
+		SymFill.hatch = (LineDEF *) 0L;
 		return true;
 	case FILE_READ:
 		ExecInput(Desc);
-		pgFill.hatch = &pgFillLine;
+		SymFill.hatch = (LineDEF *) 0L;
 		return true;
 	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "bezier", Desc);
+		return ExecOutput(Notary->RegisterGO(this), "Symbol", Desc);
 		}
 	return false;
 }
-
-bool
-rectangle::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"moveable", typNZINT, &moveable, 0L},
-		{"p1", typLFPOINT, &fp1, 0L},
-		{"p2", typLFPOINT, &fp2, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"FillLine", typLINEDEF, &FillLine, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"Rad", typNZLFLOAT, &rad, 0L},
-		{"Name", typLAST | typTEXT, &name, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		memcpy(&Line, defs.pgLineDEF(0L), sizeof(LineDEF));
-		memcpy(&Fill, defs.pgFillDEF(0L), sizeof(FillDEF));
-		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
-		Fill.hatch = &FillLine;
-		pts = 0L;	nPts = 0L;
-		rad = defs.GetSize(SIZE_RRECT_RAD);
-		drc = 0L;
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		Fill.hatch = &FillLine;
-		return true;
-	case FILE_WRITE:
-		if(type != 2) rad = 0.0;
-		ExecOutput(Notary->RegisterGO(this), 
-			type == 1? (char*)"ellipse" : type == 2? (char*)"roundrec" :
-			(char*)"rectangle", Desc);
-		return true;
-		}
-	return false;
-}
-
+
+
+bool
+Bubble::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"Pos", typLFPOINT, &fPos, 0L},
+		{"Size", typLFLOAT, &fs, 0L},
+		{"Line", typLINEDEF, &BubbleLine, 0L},
+		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
+		{"Fill", typFILLDEF, &BubbleFill, 0L},
+		{"Name", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		BubbleLine.width = DefSize(SIZE_BUBBLE_LINE);
+		BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
+		BubbleLine.color = BubbleFillLine.color = defs.Color(COL_BUBBLE_LINE);
+		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
+		ssRef = 0L;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		BubbleFill.hatch = &BubbleFillLine;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Bubble", Desc);
+		}
+	return false;
+}
+
+bool
+Bar::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"Pos", typLFPOINT, &fPos, 0L},
+		{"Size", typLFLOAT, &size, 0L},
+		{"Org", typLFPOINT, &BarBase, 0L},
+		{"Line", typLINEDEF, &BarLine, 0L},
+		{"Fill", typFILLDEF, &BarFill, 0L},
+		{"FillLine", typLINEDEF, &HatchLine, 0L},
+		{"Name", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		type = BAR_VERTB;
+		memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
+		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
+		BarFill.hatch = &HatchLine;
+		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
+		size = DefSize(SIZE_BAR);
+		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		BarFill.hatch = &HatchLine;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Bar", Desc);
+		}
+	return false;
+}
+
+void
+DataLine::FileValues(char *name, int type, double start, double step)
+{
+	FILE *file;
+	int i, c;
+	double fx;
+	lfPOINT *tfp;
+
+#ifdef USE_WIN_SECURE
+	if(fopen_s(&file, name, "r")) {
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "DataLine: open failed for file \"%s\"", name);
+#else
+	if(!(file = fopen(name, "r"))) {
+		sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
+#endif
+		ErrorBox(TmpTxt);
+		return;
+		}
+	if(Values) free(Values);
+	if(!(Values = (lfPOINT*)calloc( nPnt = 1000, sizeof(lfPOINT)))){
+		fclose(file);
+		return;
+		}
+	switch(type) {
+	case 1:				//x and y values
+		i = 0;
+		do {
+#ifdef USE_WIN_SECURE
+			c = fscanf_s(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
+#else
+			c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
+#endif
+			i++;
+			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
+				Values = tfp;			nPnt += 1000;
+				}
+			else if(i >= nPnt) break;
+			}while(c == 2);
+		i--;
+		break;
+	case 2:				//only y values
+		i = 0;	fx = start;
+		do {
+#ifdef USE_WIN_SECURE
+			c = fscanf_s(file, "%lf", &Values[i].fy);
+#else
+			c = fscanf(file, "%lf", &Values[i].fy);
+#endif
+			Values[i].fx = fx;
+			i++;	fx += step;
+			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
+				Values = tfp;			nPnt += 1000;
+				}
+			}while(c == 1);
+		i--;
+		break;
+		}
+	nPntSet = i-1;
+	fclose(file);
+}
+
+bool
+DataLine::FileIO(int rw)
+{
+	long i;
+	char *file1 = 0L;
+	char *file2 = 0L;
+	double Start = 0.0f, Step = 0.0f;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssXref", typTEXT, &ssXref, 0L},
+		{"ssYref", typTEXT, &ssYref, 0L},
+		{"BgCol", typDWORD, &BgColor, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"Data", typFPLST, &Values, &i},
+		{"file_xy", typTEXT, &file2, 0L},
+		{"start_x", typNZLFLOAT, &Start, 0L},
+		{"step_x", typNZLFLOAT, &Step, 0L},
+		{"file_y", typTEXT, &file1, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		isPolygon = false;
+		nPnt = nPntSet = cp = 0;
+		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+		BgColor = defs.Color(COL_BG);
+		pts = 0L;		dirty = true;	mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		min.fx = min.fy = max.fx = max.fy = 0.0;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		nPnt = i;
+		nPntSet = i-1;
+		if(file2)FileValues(file2, 1, 0.0, 1.0);
+		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
+		if(file1) free(file1);
+		if(file2) free(file2);
+		if(i && Values)return true;
+		break;
+	case FILE_WRITE:
+		i = nPntSet+1;
+		return ExecOutput(Notary->RegisterGO(this), "DataLine", Desc);
+		}
+	return false;
+}
+
+bool
+DataPolygon::FileIO(int rw)
+{
+	long i;
+	char *file1 = 0L;
+	char *file2 = 0L;
+	double Start = 0.0f, Step = 0.0f;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssXref", typTEXT, &ssXref, 0L},
+		{"ssYref", typTEXT, &ssYref, 0L},
+		{"BgCol", typDWORD, &BgColor, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"FillLine", typLINEDEF, &pgFillLine, 0L},
+		{"Fill", typFILLDEF, &pgFill, 0L},
+		{"Data", typFPLST, &Values, &i},
+		{"file_xy", typTEXT, &file2, 0L},
+		{"start_x", typNZLFLOAT, &Start, 0L},
+		{"step_x", typNZLFLOAT, &Step, 0L},
+		{"file_y", typLAST | typTEXT, &file1, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		isPolygon = true;
+		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+		LineDef.pattern = 0L;
+		BgColor = defs.Color(COL_BG);
+		memcpy(&pgFill, defs.GetFill(), sizeof(FillDEF));
+		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
+		pgFill.hatch = &pgFillLine;		dirty = true;	mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		min.fx = min.fy = max.fx = max.fy = 0.0f;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		nPnt = i;
+		nPntSet = i-1;
+		if(file2)FileValues(file2, 1, 0.0f, 1.0f);
+		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
+		if(file1) free(file1);
+		if(file2) free(file2);
+		pgFill.hatch = &pgFillLine;
+		if(i && Values)return true;
+		break;
+	case FILE_WRITE:
+		i = nPntSet+1;
+		return ExecOutput(Notary->RegisterGO(this), "DataPolygon", Desc);
+		}
+	return false;
+}
+
+bool
+RegLine::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"type", typNZINT, &type, 0L},
+		{"nPoints", typINT, &nPoints, 0L},
+		{"BgCol", typDWORD, &BgColor, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"Range", typFRECT, &lim, 0L},
+		{"uClip", typFRECT, &uclip, 0L},
+		{"mx", typNZLFLOAT, &mx, 0L},
+		{"my", typNZLFLOAT, &my, 0L},
+		{"li1", typLFPOINT, &l1, 0L},
+		{"li2", typLFPOINT, &l2, 0L},
+		{"li3", typLFPOINT, &l3, 0L},
+		{"li4", typLFPOINT, &l4, 0L},
+		{"li5", typLAST | typLFPOINT, &l5, 0L}};
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		cp = 0;
+		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+		BgColor = defs.Color(COL_BG);
+		pts = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "RegLine", Desc);
+		}
+	return false;
+}
+
+void
+SDellipse::RegGO(void *n)
+{
+	if(n) {
+		if(rl)rl->RegGO(n);
+		((notary*)n)->AddRegGO(this);
+	}
+}
+
+bool
+SDellipse::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"type", typNZINT, &type, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"Range", typFRECT, &lim, 0L},
+		{"Regr", typGOBJ, &rl, 0L},
+		{"Data", typLAST | typFPLST, &val, &nPoints}};
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		memcpy(&LineDef, defs.GetOutLine(), sizeof(LineDEF));
+		pts = 0L;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(rl) rl->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(rl) rl->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "SDellipse", Desc);
+		}
+	return false;
+}
+
+bool
+ErrorBar::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"Pos", typLFPOINT, &fPos, 0L},
+		{"Err", typLFLOAT, &ferr, 0L},
+		{"Size", typLFLOAT, &SizeBar, 0L},
+		{"Line", typLINEDEF, &ErrLine, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		SizeBar = DefSize(SIZE_ERRBAR);
+		ErrLine.width = DefSize(SIZE_ERRBAR_LINE);
+		ErrLine.color = defs.Color(COL_SYM_LINE);
+		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "ErrorBar", Desc);
+		}
+	return false;
+}
+
+bool
+Arrow::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"p1", typLFPOINT, &pos1, 0L},
+		{"p2", typLFPOINT, &pos2, 0L},
+		{"CapW", typLFLOAT, &cw, 0L},
+		{"CapL", typLFLOAT, &cl, 0L},
+		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		cw = DefSize(SIZE_ARROW_CAPWIDTH);
+		cl = DefSize(SIZE_ARROW_CAPLENGTH);
+		LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
+		LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : DefSize(SIZE_ARROW_LINE);
+		type = ARROW_LINE;
+		dh1 = dh2 = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Arrow", Desc);
+		}
+	return false;
+}
+
+bool
+Box::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"High", typLFPOINT, &pos1, 0L},
+		{"Low", typLFPOINT, &pos2, 0L},
+		{"Size", typLFLOAT, &size, 0L},
+		{"Line", typLINEDEF, &Outline, 0L},
+		{"FillLine", typLINEDEF, &Hatchline, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Name", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		memcpy(&Outline, defs.GetOutLine(), sizeof(LineDEF));
+		memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
+		if(Fill.hatch)memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
+		Fill.hatch = &Hatchline;
+		size = DefSize(SIZE_BAR);
+		ssRef = 0L;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		Fill.hatch = &Hatchline;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Box", Desc);
+		}
+	return false;
+}
+
+bool
+Whisker::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"High", typLFPOINT, &pos1, 0L},
+		{"Low", typLFPOINT, &pos2, 0L},
+		{"Size", typLFLOAT, &size, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		size = DefSize(SIZE_WHISKER);
+		LineDef.width = DefSize(SIZE_WHISKER_LINE);
+		LineDef.color = defs.Color(COL_WHISKER);
+		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Whisker", Desc);
+		}
+	return false;
+}
+
+bool
+DropLine::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typINT, &type, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"Pos", typLFPOINT, &fPos, 0L},
+		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		LineDef.color = defs.Color(COL_SYM_LINE);
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "DropLine", Desc);
+		}
+	return false;
+}
+
+bool
+Sphere::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Pos", typPOINT3D, &fPos, 0L},
+		{"Size", typLFLOAT, &size, 0L},
+		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		size = DefSize(SIZE_SYMBOL);
+		Line.color = defs.Color(COL_SYM_LINE);
+		Line.width = DefSize(SIZE_SYM_LINE);
+		Fill.color = defs.Color(COL_SYM_FILL);
+		scl = 0L;		nscl = 0;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Sphere", Desc);
+		}
+	return false;
+}
+
+bool
+Plane3D::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"values", typLAST | typFPLST3D, &dt, &ndt}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		ipl = 0L;	pts = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Plane3D", Desc);
+		}
+	return false;
+}
+
+bool
+Brick::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Pos", typPOINT3D, &fPos, 0L},
+		{"depth", typLFLOAT, &depth, 0L},
+		{"width", typLFLOAT, &width, 0L},
+		{"height", typLFLOAT, &height, 0L},
+		{"flags", typDWORD, &flags, 0L},
+		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		Line.color = defs.Color(COL_SYM_LINE);
+		Line.width = DefSize(SIZE_SYM_LINE);
+		Fill.color = defs.Color(COL_SYM_FILL);
+		faces = (plane**)calloc(6, sizeof(plane*));
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		mo = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Brick", Desc);
+		}
+	return false;
+}
+
+bool
+DropLine3D::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typINT, &type, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Pos", typPOINT3D, &fPos, 0L},
+		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		Line.color = defs.Color(COL_SYM_LINE);
+		Line.width = DefSize(SIZE_HAIRLINE);	mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		ls[0] = ls[1] = ls[2] = ls[3] = ls[4] = ls[5] = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "DropLine3D", Desc);
+		}
+	return false;
+}
+
+bool
+Arrow3D::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typINT, &type, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Org", typPOINT3D, &fPos1, 0L},
+		{"Pos", typPOINT3D, &fPos2, 0L},
+		{"CapW", typLFLOAT, &cw, 0L},
+		{"CapL", typLFLOAT, &cl, 0L},
+		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		cw = DefSize(SIZE_ARROW_CAPWIDTH);
+		cl = DefSize(SIZE_ARROW_CAPLENGTH);
+		Line.color = defs.Color(COL_ARROW);
+		Line.width = DefSize(SIZE_ARROW_LINE);
+		ls[0] = ls[1] = ls[2] = 0L;
+		cap = 0L;
+		type = ARROW_LINE;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Arrow3D", Desc);
+		}
+	return false;
+}
+
+bool
+Line3D::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Line", typLINEDEF, &Line, 0L},
+		{"ssRefX", typTEXT, &x_range, 0L},
+		{"ssRefY", typTEXT, &y_range, 0L},
+		{"ssRefZ", typTEXT, &z_range, 0L},
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"values", typLAST | typFPLST3D, &values, &nPts}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		Line.color = defs.Color(COL_DATA_LINE);
+		Line.width = DefSize(SIZE_DATA_LINE);
+		ls = 0L;	pts = 0L;	npts = 0L;	mo=0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		min.fx = min.fy = min.fz = max.fx = max.fy = max.fz = 0.0;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(nPts > 1) ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Line3D", Desc);
+		}
+	return false;
+}
+
+bool
+Label::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"ssRef", typIPLST, &ssRef, &cssRef},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Pos", typNZLFPOINT, &fPos, 0L},
+		{"Dist", typNZLFPOINT, &fDist, 0L},
+		{"Flags", typDWORD, &flags, 0L},
+		{"TxtDef", typLAST | typTXTDEF, &TextDef, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		TextDef.ColTxt = 0x0L;
+		TextDef.ColBg = 0x00ffffffL;
+		TextDef.fSize = DefSize(SIZE_TEXT);
+		TextDef.RotBL = TextDef.RotCHAR = 0.0;
+		TextDef.iSize = 0;
+		TextDef.Align = TXA_VTOP | TXA_HLEFT;
+		TextDef.Mode = TXM_TRANSPARENT;
+		TextDef.Style = TXS_NORMAL;
+		TextDef.Font = FONT_HELVETICA;
+		TextDef.text = 0L;	bgcolor = 0x00ffffffL;
+		bgLine.width = 0.0;		bgLine.patlength = 6.0;
+		bgLine.color = bgcolor;	bgLine.pattern = 0L;
+		CursorPos = 0;	defDisp = 0L;	bBGvalid = bModified = false;
+		curr_z = 0.0;		is3D = false;	fmt_txt = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(parent && parent->Id != GO_MLABEL) {
+			if(!TextDef.text || !TextDef.text[0]) return false;
+			}
+		return ExecOutput(Notary->RegisterGO(this), "Label", Desc);
+		}
+	return false;
+}
+
+void
+mLabel::RegGO(void *n)
+{
+	int i;
+
+	if(n) {
+		if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]) Lines[i]->RegGO(n);
+		((notary*)n)->AddRegGO(this);
+	}
+}
+
+bool
+mLabel::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Pos", typNZLFPOINT, &fPos, 0L},
+		{"Dist", typNZLFPOINT, &fDist, 0L},
+		{"lspc", typLFLOAT, &lspc, 0L},
+		{"Flags", typDWORD, &flags, 0L},
+		{"TxtDef", typTXTDEF, &TextDef, 0L},
+		{"Lines", typLAST | typOBJLST, &Lines, &nLines}};
+	int i;
+
+	switch(rw) {
+	case SAVE_VARS:
+		//The lines inherit settings from this object.
+		//We need not save them in this context
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		TextDef.ColTxt = 0x0L;
+		TextDef.ColBg = 0x00ffffffL;
+		TextDef.fSize = DefSize(SIZE_TEXT);
+		TextDef.RotBL = TextDef.RotCHAR = 0.0;
+		TextDef.iSize = 0;
+		TextDef.Align = TXA_VTOP | TXA_HLEFT;
+		TextDef.Mode = TXM_TRANSPARENT;
+		TextDef.Style = TXS_NORMAL;
+		TextDef.Font = FONT_HELVETICA;
+		TextDef.text = 0L;
+		undo_flags = 0L;	lspc = 1.0;
+		curr_z = 0.0;		is3D = false;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(Lines) for ( i = 0; i < nLines; i++)
+			if(Lines[i]) Lines[i]->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(Lines) for ( i = 0; i < nLines; i++)
+			if(Lines[i]) Lines[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "mLabel", Desc);
+		}
+	return false;
+}
+
+bool
+TextFrame::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Pos1", typNZLFPOINT, &pos1, 0L},
+		{"Pos2", typNZLFPOINT, &pos2, 0L},
+		{"lspc", typLFLOAT, &lspc, 0L},
+		{"Pad", typFRECT, &pad, 0L},
+		{"TxtDef", typTXTDEF, &TextDef, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"FillLine", typLINEDEF, &FillLine, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Text", typLAST | typTEXT, &text, 0L}};
+	switch(rw) {
+	case SAVE_VARS:
+		return false;
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		TextDef.ColTxt = 0x0L;
+		TextDef.ColBg = 0x00ffffffL;
+		TextDef.fSize = DefSize(SIZE_TEXT);
+		TextDef.RotBL = TextDef.RotCHAR = 0.0;
+		TextDef.iSize = 0;
+		TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
+		TextDef.Mode = TXM_TRANSPARENT;
+		TextDef.Style = TXS_NORMAL;
+		TextDef.Font = FONT_HELVETICA;
+		TextDef.text = 0L;
+		lines = 0L;		nlines = 0;			drc = 0L;
+		cur_pos.x = cur_pos.y = tm_c = 0;	tm_rec = 0L;
+		bModified = bResize = has_m1 = has_m2 = false;
+		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
+		Fill.hatch = &FillLine;			c_char = m1_char = m2_char = '?';
+		pad.Xmin = pad.Xmax = pad.Ymin = pad.Ymax = DefSize(SIZE_SYMBOL)/2.0;
+		Cursor.left = Cursor.right = Cursor.top = Cursor.bottom = 0;
+		pad.Xmax *= 2.0;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);				Fill.hatch = &FillLine;
+		return true;
+	case FILE_WRITE:
+		if(lines)lines2text();
+		if(!text || !text[0]) return false;
+		return ExecOutput(Notary->RegisterGO(this), "TextFrame", Desc);
+		}
+	return false;
+}
+
+bool
+segment::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"moveable", typNZINT, &moveable, 0L},
+		{"cent", typLFPOINT, &fCent, 0L},
+		{"ri", typNZLFLOAT, &radius1, 0L},
+		{"ra", typLFLOAT, &radius2, 0L},
+		{"start", typLFLOAT, &angle1, 0L},
+		{"end", typLFLOAT, &angle2, 0L},
+		{"shout", typNZLFLOAT, &shift, 0L},
+		{"Line", typLINEDEF, &segLine, 0L},
+		{"FillLine", typLINEDEF, &segFillLine, 0L},
+		{"Fill", typLAST | typFILLDEF, &segFill, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		segLine.width = DefSize(SIZE_SEGLINE);
+		pts = 0L;	nPts = 0;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		segFill.hatch = &segFillLine;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "segment", Desc);
+		}
+	return false;
+}
+
+bool
+polyline::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Data", typFPLST, &Values, &nPoints},
+		{"Line", typLINEDEF, &pgLine, 0L},
+		{"FillLine", typLINEDEF, &pgFillLine, 0L},
+		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
+	
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		memcpy(&pgLine, defs.plLineDEF(0L), sizeof(LineDEF));
+		memcpy(&pgFill, defs.pgFillDEF(0L), sizeof(FillDEF));
+		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
+		pgFill.hatch = &pgFillLine;
+		pts = 0L;		nPts = 0;
+		pHandles = 0L;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		pgFill.hatch = &pgFillLine;
+		return true;
+	case FILE_WRITE:
+		if(type != 1) Desc[3].type |= typLAST;	//skip fill for polyline
+		return ExecOutput(Notary->RegisterGO(this), 
+			type == 1 ? (char*)"polygon" : (char*)"polyline", Desc);
+		}
+	return false;
+}
+
+bool
+Bezier::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Data", typFPLST, &Values, &nPoints},
+		{"Line", typLINEDEF, &pgLine, 0L},
+		{"FillLine", typLINEDEF, &pgFillLine, 0L},
+		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
+	
+	switch(rw) {
+	case INIT_VARS:
+		//assume that all initialization is done by polyline::FileIO(int rw)
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		pgFill.hatch = &pgFillLine;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "bezier", Desc);
+		}
+	return false;
+}
+
+bool
+rectangle::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"p1", typLFPOINT, &fp1, 0L},
+		{"p2", typLFPOINT, &fp2, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"FillLine", typLINEDEF, &FillLine, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Rad", typNZLFLOAT, &rad, 0L},
+		{"Name", typLAST | typTEXT, &name, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		memcpy(&Line, defs.pgLineDEF(0L), sizeof(LineDEF));
+		memcpy(&Fill, defs.pgFillDEF(0L), sizeof(FillDEF));
+		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
+		Fill.hatch = &FillLine;
+		pts = 0L;	nPts = 0L;
+		rad = DefSize(SIZE_RRECT_RAD);
+		drc = 0L;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		Fill.hatch = &FillLine;
+		return true;
+	case FILE_WRITE:
+		if(type != 2) rad = 0.0;
+		ExecOutput(Notary->RegisterGO(this), 
+			type == 1? (char*)"ellipse" : type == 2? (char*)"roundrec" :
+			(char*)"rectangle", Desc);
+		return true;
+		}
+	return false;
+}
+
 void
 LegItem::RegGO(void *n)
 {
@@ -2085,40 +2242,40 @@ LegItem::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-LegItem::FileIO(int rw)
-{
-	descIO Des[] = {
-		{"D_Line", typLINEDEF, &DataLine, 0L},
-		{"O_Line", typLINEDEF, &OutLine, 0L},
-		{"H_Line", typLINEDEF, &HatchLine, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"Sym", typGOBJ, &Sym, 0L},
-		{"Text", typGOBJ, &Desc, 0L},
-		{"flags", typLAST | typDWORD, &flags, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Des);
-	case INIT_VARS:
-		InitVarsGO(Des);
-		Fill.hatch = &HatchLine;
-		return true;
-	case FILE_READ:
-		ExecInput(Des);
-		Fill.hatch = &HatchLine;
-		if(Sym) Sym->parent=this;
-		if(Desc) Desc->parent=this;
-		return true;
-	case FILE_WRITE:
-		if(Sym) Sym->FileIO(rw);
-		if(Desc) Desc->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "LegItem", Des);
-		}
-	return false;
-}
-
+
+bool
+LegItem::FileIO(int rw)
+{
+	descIO Des[] = {
+		{"D_Line", typLINEDEF, &DataLine, 0L},
+		{"O_Line", typLINEDEF, &OutLine, 0L},
+		{"H_Line", typLINEDEF, &HatchLine, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"Sym", typGOBJ, &Sym, 0L},
+		{"Text", typGOBJ, &Desc, 0L},
+		{"flags", typLAST | typDWORD, &flags, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Des);
+	case INIT_VARS:
+		InitVarsGO(Des);
+		Fill.hatch = &HatchLine;
+		return true;
+	case FILE_READ:
+		ExecInput(Des);
+		Fill.hatch = &HatchLine;
+		if(Sym) Sym->parent=this;
+		if(Desc) Desc->parent=this;
+		return true;
+	case FILE_WRITE:
+		if(Sym) Sym->FileIO(rw);
+		if(Desc) Desc->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "LegItem", Des);
+		}
+	return false;
+}
+
 void
 Legend::RegGO(void *n)
 {
@@ -2129,47 +2286,49 @@ Legend::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Legend::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"pos", typLFPOINT, &pos, 0L},
-		{"rec1", typFRECT, &B_Rect, 0L},
-		{"rec2", typFRECT, &D_Rect, 0L},
+
+bool
+Legend::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"pos", typLFPOINT, &pos, 0L},
+		{"rec1", typFRECT, &B_Rect, 0L},
+		{"rec2", typFRECT, &D_Rect, 0L},
 		{"rec3", typFRECT, &F_Rect, 0L},
-		{"Items", typLAST | typOBJLST, &Items, &nItems}};
-	int i;
-	double d;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		B_Rect.Ymin = defs.GetSize(SIZE_DRECT_TOP);
-		B_Rect.Xmin = defs.GetSize(SIZE_DRECT_LEFT);
-		B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = defs.GetSize(SIZE_BAR));
-		B_Rect.Ymin += d*0.2;
-		B_Rect.Ymax = B_Rect.Ymin + d/2.0;
-		D_Rect.Ymin = 0.0;			D_Rect.Xmin = d*0.7;
-		D_Rect.Xmax = d*1.3;		D_Rect.Ymax = d*0.4;
+		{"Items", typLAST | typOBJLST, &Items, &nItems}};
+	int i;
+	double d;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		B_Rect.Ymin = DefSize(SIZE_DRECT_TOP);			B_Rect.Xmin = DefSize(SIZE_DRECT_LEFT);
+		B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = DefSize(SIZE_BAR));
+		B_Rect.Ymin += d*0.2;
+		B_Rect.Ymax = B_Rect.Ymin + d/2.0;
+		D_Rect.Ymin = 0.0;			D_Rect.Xmin = d*0.7;
+		D_Rect.Xmax = d*1.3;		D_Rect.Ymax = d*0.4;
 		F_Rect.Ymin = 0.0;			F_Rect.Xmin = d*0.2;
 		F_Rect.Xmax = d*1.3;		F_Rect.Ymax = d*0.4;
-		to = 0L;					hasLine = false;
+		to = 0L;					hasLine = false;
 		trc.left = trc.right = trc.top = trc.bottom = 0;
-		if(!name) name=strdup("Legend");
-		return true;
-	case FILE_READ:
-		nItems = 0L;
-		ExecInput(Desc);
-		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->parent=this;
-		return true;
-	case FILE_WRITE:
-		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Legend", Desc);
-		}
-	return false;
-}
-
+		if(!name) {
+			name = (char*)malloc(20 * sizeof(char));
+			rlp_strcpy(name, 20, "Legend");
+			}
+		return true;
+	case FILE_READ:
+		nItems = 0L;
+		ExecInput(Desc);
+		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->parent=this;
+		return true;
+	case FILE_WRITE:
+		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Legend", Desc);
+		}
+	return false;
+}
+
 void
 PlotScatt::RegGO(void *n)
 {
@@ -2187,46 +2346,53 @@ PlotScatt::RegGO(void *n)
 		}
 }
 
-bool
-PlotScatt::FileIO(int rw)
-{
+bool
+PlotScatt::FileIO(int rw)
+{
 	descIO Desc[] = {
-		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"DefSym", typNZINT, &DefSym, 0L},
-		{"baDist", typLFPOINT, &BarDist, 0L},
-		{"xRange", typTEXT, &xRange, 0L},
-		{"yRange", typTEXT, &yRange, 0L},
-		{"eRange", typTEXT, &ErrRange, 0L},
-		{"lRange", typTEXT, &LbRange, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"Bars", typOBJLST, &Bars, &nPoints},
-		{"Symbols", typOBJLST, &Symbols, &nPoints},
-		{"PL", typGOBJ, &TheLine, 0L},
-		{"ErrBars", typOBJLST, &Errors, &nPoints},
-		{"Arrows", typOBJLST, &Arrows, &nPoints},
-		{"dLines", typOBJLST, &DropLines, &nPoints},
-		{"Labels", typLAST | typOBJLST, &Labels, &nPoints}};
+		{"hide", typNZINT, &hidden, 0L},
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"DefSym", typNZINT, &DefSym, 0L},
+		{"baDist", typLFPOINT, &BarDist, 0L},
+		{"xRange", typTEXT, &xRange, 0L},
+		{"yRange", typTEXT, &yRange, 0L},
+		{"eRange", typTEXT, &ErrRange, 0L},
+		{"lRange", typTEXT, &LbRange, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"Bars", typOBJLST, &Bars, &nPoints},
+		{"Symbols", typOBJLST, &Symbols, &nPoints},
+		{"PL", typGOBJ, &TheLine, 0L},
+		{"ErrBars", typOBJLST, &Errors, &nPoints},
+		{"Arrows", typOBJLST, &Arrows, &nPoints},
+		{"dLines", typOBJLST, &DropLines, &nPoints},
+		{"Labels", typOBJLST, &Labels, &nPoints},
+		{"x_info", typTEXT, &x_info, 0L},
+		{"y_info", typLAST | typTEXT, &y_info, 0L}};
 	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		DefSym = SYM_CIRCLE;
-		DefSel = 0x01;
-		dirty = true;
+
+	switch(rw) {
+	case INIT_VARS:
+		x_info = y_info = z_info = 0L;
+		InitVarsGO(Desc);
+		DefSym = SYM_CIRCLE;
+		DefSel = 0x01;
+		dirty = true;
 		if(name) {
-			sprintf(TmpTxt, "xy-plot (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xy-plot (%s)", name);
+#else
+			i = sprintf(TmpTxt, "xy-plot (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		nPoints = 0L;
+		return true;
+	case FILE_READ:
+		nPoints = 0L;
 		ExecInput(Desc);
 		ForEach(FE_PARENT, 0L, 0L);
-		return true;
-	case FILE_WRITE:
+		return true;
+	case FILE_WRITE:
 		if(TheLine) TheLine->FileIO(rw);
 		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
 		if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->FileIO(rw);
@@ -2234,9 +2400,9 @@ PlotScatt::FileIO(int rw)
 		if(DropLines) for(i = 0; i < nPoints; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
 		if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->FileIO(rw);
 		if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "PlotScatt", Desc);
-		}
-	return false;
+		return ExecOutput(Notary->RegisterGO(this), "PlotScatt", Desc);
+		}
+	return false;
 }
 
 bool
@@ -2258,7 +2424,9 @@ xyStat::FileIO(int rw)
 		{"Symbols", typOBJLST, &Symbols, &nPoints},
 		{"PL", typGOBJ, &TheLine, 0L},
 		{"ErrBars", typOBJLST, &Errors, &nPoints},
-		{"Labels", typLAST | typOBJLST, &Labels, &nPoints}};
+		{"Labels", typOBJLST, &Labels, &nPoints},
+		{"x_info", typTEXT, &x_info, 0L},
+		{"y_info", typLAST | typTEXT, &y_info, 0L}};
 	int i;
 
 	switch(rw) {
@@ -2296,7 +2464,7 @@ FreqDist::RegGO(void *n)
 }
 
 bool
-FreqDist::FileIO(int rw)
+FreqDist::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
@@ -2320,11 +2488,14 @@ FreqDist::FileIO(int rw)
 		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
 		BarFill.hatch = &HatchLine;
 		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
-		curr_data=0L;
-		dirty = true;
+		curr_data=0L;		dirty = true;
 		if(name) {
-			sprintf(TmpTxt, "freq. dist. (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "freq. dist. (%s)", name);
+#else
+			i = sprintf(TmpTxt, "freq. dist. (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
 		return true;
 	case FILE_READ:
@@ -2350,44 +2521,48 @@ Regression::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Regression::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
+
+bool
+Regression::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"xRange", typTEXT, &xRange, 0L},
-		{"yRange", typTEXT, &yRange, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"Line", typGOBJ, &rLine, 0L},
-		{"Ellipse", typGOBJ, &sde, 0L},
-		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		dirty = true;
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"xRange", typTEXT, &xRange, 0L},
+		{"yRange", typTEXT, &yRange, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"Line", typGOBJ, &rLine, 0L},
+		{"Ellipse", typGOBJ, &sde, 0L},
+		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		dirty = true;
 		if(name) {
-			sprintf(TmpTxt, "regression (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "regression (%s)", name);
+#else
+			i = sprintf(TmpTxt, "regression (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		nPoints = 0L;
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(rLine) rLine->FileIO(rw);
-		if(sde) sde->FileIO(rw);
-		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Regression", Desc);
-		}
-	return false;
-}
-
+		return true;
+	case FILE_READ:
+		nPoints = 0L;
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(rLine) rLine->FileIO(rw);
+		if(sde) sde->FileIO(rw);
+		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Regression", Desc);
+		}
+	return false;
+}
+
 void
 BubblePlot::RegGO(void *n)
 {
@@ -2399,44 +2574,48 @@ BubblePlot::RegGO(void *n)
 		}
 }
 
-bool
-BubblePlot::FileIO(int rw)
-{
-	descIO Desc[] = {
+bool
+BubblePlot::FileIO(int rw)
+{
+	descIO Desc[] = {
 		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"Line", typLINEDEF, &BubbleLine, 0L},
-		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
-		{"Fill", typFILLDEF, &BubbleFill, 0L},
-		{"Bubbles", typLAST | typOBJLST, &Bubbles, &nPoints}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
-		BubbleLine.color = defs.Color(COL_BUBBLE_LINE);
-		BubbleLine.width = defs.GetSize(SIZE_BUBBLE_LINE);
-		BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
-		BubbleFillLine.width = defs.GetSize(SIZE_BUBBLE_HATCH_LINE);
-		BubbleFill.hatch = &BubbleFillLine;
-		dirty = true;
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"Line", typLINEDEF, &BubbleLine, 0L},
+		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
+		{"Fill", typFILLDEF, &BubbleFill, 0L},
+		{"Bubbles", typLAST | typOBJLST, &Bubbles, &nPoints}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
+		BubbleLine.color = defs.Color(COL_BUBBLE_LINE);
+		BubbleLine.width = DefSize(SIZE_BUBBLE_LINE);
+		BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
+		BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
+		BubbleFill.hatch = &BubbleFillLine;
+		dirty = true;
 		if(name) {
-			sprintf(TmpTxt, "bubbles (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "bubbles (%s)", name);
+#else
+			i = sprintf(TmpTxt, "bubbles (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "BubblePlot", Desc);
-		}
-	return false;
-}
-
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "BubblePlot", Desc);
+		}
+	return false;
+}
+
 void
 PolarPlot::RegGO(void *n)
 {
@@ -2448,40 +2627,44 @@ PolarPlot::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-PolarPlot::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
+
+bool
+PolarPlot::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"ang_offs", typLFLOAT, &offs, 0L},
-		{"Plots", typOBJLST, &Plots, (long*)&nPlots},
-		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
-		{"FillLine", typLINEDEF, &FillLine, 0L},
-		{"Fill", typLAST | typFILLDEF, &Fill, 0L}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		CurrDisp = 0L;
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"ang_offs", typLFLOAT, &offs, 0L},
+		{"Plots", typOBJLST, &Plots, (long*)&nPlots},
+		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
+		{"FillLine", typLINEDEF, &FillLine, 0L},
+		{"Fill", typLAST | typFILLDEF, &Fill, 0L}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		CurrDisp = 0L;
 		InitVarsGO(Desc);
 		if(name) {
-			sprintf(TmpTxt, "polar root (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "polar root (%s)", name);
+#else
+			i = sprintf(TmpTxt, "polar root (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
-		if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "PolarPlot", Desc);
-		}
-	return false;
-}
-
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+		if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "PolarPlot", Desc);
+		}
+	return false;
+}
+
 void
 BoxPlot::RegGO(void *n)
 {
@@ -2496,55 +2679,58 @@ BoxPlot::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-BoxPlot::FileIO(int rw)
-{
+
+bool
+BoxPlot::FileIO(int rw)
+{
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
+		{"Bounds", typFRECT, &Bounds, 0L},
 		{"xRange", typTEXT, &xRange, 0L},
 		{"yRange", typTEXT, &yRange, 0L},
 		{"prefix", typTEXT, &case_prefix, 0L},
 		{"boDist", typLFPOINT, &BoxDist, 0L},
 		{"ci_box", typNZLFLOAT, &ci_box, 0L},
-		{"ci_err", typNZLFLOAT, &ci_err, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"Boxes", typOBJLST, &Boxes, &nPoints},
-		{"Whiskers", typOBJLST, &Whiskers, &nPoints},
-		{"Symbols", typOBJLST, &Symbols, &nPoints},
+		{"ci_err", typNZLFLOAT, &ci_err, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"Boxes", typOBJLST, &Boxes, &nPoints},
+		{"Whiskers", typOBJLST, &Whiskers, &nPoints},
+		{"Symbols", typOBJLST, &Symbols, &nPoints},
 		{"Labels", typOBJLST, &Labels, &nPoints},
-		{"Line", typLAST | typGOBJ, &TheLine, 0L}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		dirty = true;
-		InitVarsGO(Desc);
+		{"Line", typLAST | typGOBJ, &TheLine, 0L}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		dirty = true;		InitVarsGO(Desc);
 		if(name) {
-			sprintf(TmpTxt, "boxes (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "boxes (%s)", name);
+#else
+			i = sprintf(TmpTxt, "boxes (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
 		curr_data = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Boxes) for(i = 0; i < nPoints; i++) 
-			if(Boxes[i]) Boxes[i]->FileIO(rw);
-		if(Whiskers) for(i = 0; i < nPoints; i++) 
-			if(Whiskers[i]) Whiskers[i]->FileIO(rw);
-		if(Symbols) for(i = 0; i < nPoints; i++) 
-			if(Symbols[i]) Symbols[i]->FileIO(rw);
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Boxes) for(i = 0; i < nPoints; i++) 
+			if(Boxes[i]) Boxes[i]->FileIO(rw);
+		if(Whiskers) for(i = 0; i < nPoints; i++) 
+			if(Whiskers[i]) Whiskers[i]->FileIO(rw);
+		if(Symbols) for(i = 0; i < nPoints; i++) 
+			if(Symbols[i]) Symbols[i]->FileIO(rw);
 		if(Labels) for(i = 0; i < nPoints; i++) 
 			if(Labels[i]) Labels[i]->FileIO(rw);
-		if(TheLine) TheLine->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "BoxPlot", Desc);
-		}
-	return false;
-}
+		if(TheLine) TheLine->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "BoxPlot", Desc);
+		}
+	return false;
+}
 
 void
 DensDisp::RegGO(void *n)
@@ -2558,33 +2744,33 @@ DensDisp::RegGO(void *n)
 }
 
 bool
-DensDisp::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
+DensDisp::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"xRange", typTEXT, &xRange, 0L},
-		{"yRange", typTEXT, &yRange, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"Line", typLINEDEF, &DefLine, 0L},
-		{"FillLine", typLINEDEF, &DefFillLine, 0L},
-		{"Fill", typFILLDEF, &DefFill, 0L},
-		{"Boxes", typLAST | typOBJLST, &Boxes, &nPoints}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		return InitVarsGO(Desc);
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "DensDisp", Desc);
-		}
-	return false;
-}
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"xRange", typTEXT, &xRange, 0L},
+		{"yRange", typTEXT, &yRange, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"Line", typLINEDEF, &DefLine, 0L},
+		{"FillLine", typLINEDEF, &DefFillLine, 0L},
+		{"Fill", typFILLDEF, &DefFill, 0L},
+		{"Boxes", typLAST | typOBJLST, &Boxes, &nPoints}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		return InitVarsGO(Desc);
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "DensDisp", Desc);
+		}
+	return false;
+}
 
 void
 StackBar::RegGO(void *n)
@@ -2600,47 +2786,51 @@ StackBar::RegGO(void *n)
 		}
 }
 
-bool
-StackBar::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Bounds", typFRECT, &Bounds, 0L},
+bool
+StackBar::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Bounds", typFRECT, &Bounds, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"x_axis", typNZINT, &use_xaxis, 0L},
-		{"y_axis", typNZINT, &use_yaxis, 0L},
-		{"cumData", typNZINT, &cum_data_mode, 0L},
-		{"StartVal", typNZLFLOAT, &StartVal, 0L},
-		{"Dspm", typNZLFPOINT, &dspm, 0L},
-		{"ssXrange", typTEXT, &ssXrange, 0L},
-		{"ssYrange", typTEXT, &ssYrange, 0L},
-		{"BoxBars", typOBJLST, &Boxes, (long*)&numPlots},
-		{"Plots", typOBJLST, &xyPlots, (long*)&numXY},
-		{"Polygons", typOBJLST, &Polygons, (long*)&numPG},
-		{"Lines", typLAST | typOBJLST, &Lines, (long*)&numPL}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		dirty = true;	CumData = 0L;
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"cumData", typNZINT, &cum_data_mode, 0L},
+		{"StartVal", typNZLFLOAT, &StartVal, 0L},
+		{"Dspm", typNZLFPOINT, &dspm, 0L},
+		{"ssXrange", typTEXT, &ssXrange, 0L},
+		{"ssYrange", typTEXT, &ssYrange, 0L},
+		{"BoxBars", typOBJLST, &Boxes, (long*)&numPlots},
+		{"Plots", typOBJLST, &xyPlots, (long*)&numXY},
+		{"Polygons", typOBJLST, &Polygons, (long*)&numPG},
+		{"Lines", typLAST | typOBJLST, &Lines, (long*)&numPL}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		dirty = true;	CumData = 0L;
 		InitVarsGO(Desc);
 		if(name) {
-			sprintf(TmpTxt, "stack (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "stack (%s)", name);
+#else
+			i = sprintf(TmpTxt, "stack (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
+		return true;
 	case FILE_READ:
-		ExecInput(Desc);
-		return true;
-	case FILE_WRITE:
-		if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
-		if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->FileIO(rw);
-		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
-		if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Stacked", Desc);
-		}
-	return false;
-}
-
+		ExecInput(Desc);
+		return true;
+	case FILE_WRITE:
+		if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
+		if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->FileIO(rw);
+		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
+		if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Stacked", Desc);
+		}
+	return false;
+}
+
 void
 PieChart::RegGO(void *n)
 {
@@ -2651,40 +2841,44 @@ PieChart::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-PieChart::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"ssRefA", typTEXT, &ssRefA, 0L},
-		{"ssRefR", typTEXT, &ssRefR, 0L},
+
+bool
+PieChart::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"ssRefA", typTEXT, &ssRefA, 0L},
+		{"ssRefR", typTEXT, &ssRefR, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"CtDef", typLFPOINT, &CtDef, 0L},
-		{"FacRad", typLFLOAT, &FacRad, 0L},
-		{"Segs", typLAST | typOBJLST, &Segments, (long*)&nPts}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		Bounds.Xmax = Bounds.Ymax = 100.0f;
-		Bounds.Xmin = Bounds.Ymin = -100.0f;
-		InitVarsGO(Desc);
-		CtDef.fx = 90.0;	CtDef.fy = 360.0;
-		FacRad = 1.0;
+		{"CtDef", typLFPOINT, &CtDef, 0L},
+		{"FacRad", typLFLOAT, &FacRad, 0L},
+		{"Segs", typLAST | typOBJLST, &Segments, (long*)&nPts}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		Bounds.Xmax = Bounds.Ymax = 100.0f;
+		Bounds.Xmin = Bounds.Ymin = -100.0f;
+		InitVarsGO(Desc);
+		CtDef.fx = 90.0;	CtDef.fy = 360.0;
+		FacRad = 1.0;
 		if(name) {
-			sprintf(TmpTxt, "pie chart (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "pie chart (%s)", name);
+#else
+			i = sprintf(TmpTxt, "pie chart (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "SegChart", Desc);
-		}
-	return false;
-}
-
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "SegChart", Desc);
+		}
+	return false;
+}
+
 void
 GoGroup::RegGO(void *n)
 {
@@ -2695,29 +2889,29 @@ GoGroup::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-GoGroup::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Pos", typNZLFPOINT, &fPos, 0L},
+
+bool
+GoGroup::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Pos", typNZLFPOINT, &fPos, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Items", typLAST | typOBJLST, &Objects, (long*)&nObs}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		Bounds.Xmax = Bounds.Ymax = 100.0f;
-		Bounds.Xmin = Bounds.Ymin = -100.0f;
-		return InitVarsGO(Desc);
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "group", Desc);
-		}
-	return false;
-}
+		{"Items", typLAST | typOBJLST, &Objects, (long*)&nObs}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		Bounds.Xmax = Bounds.Ymax = 100.0f;
+		Bounds.Xmin = Bounds.Ymin = -100.0f;
+		return InitVarsGO(Desc);
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "group", Desc);
+		}
+	return false;
+}
 
 void
 Scatt3D::RegGO(void *n)
@@ -2734,58 +2928,62 @@ Scatt3D::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Scatt3D::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"ssRefX", typTEXT, &ssRefX, 0L},
-		{"ssRefY", typTEXT, &ssRefY, 0L},
-		{"ssRefZ", typTEXT, &ssRefZ, 0L},
+
+bool
+Scatt3D::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"ssRefX", typTEXT, &ssRefX, 0L},
+		{"ssRefY", typTEXT, &ssRefY, 0L},
+		{"ssRefZ", typTEXT, &ssRefZ, 0L},
 		{"hide", typNZINT, &hidden, 0L},
-		{"Line", typGOBJ, &Line, 0L},
-		{"Balls", typOBJLST, &Balls, &nBalls},
-		{"Columns", typOBJLST, &Columns, &nColumns},
+		{"Line", typGOBJ, &Line, 0L},
+		{"Balls", typOBJLST, &Balls, &nBalls},
+		{"Columns", typOBJLST, &Columns, &nColumns},
 		{"DropLines", typOBJLST, &DropLines, &nDropLines},
-		{"ParaV", typGOBJ, &rib, 0L},
-		{"Arrows", typLAST | typOBJLST, &Arrows, &nArrows}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		c_flags = 0L;
-		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
-		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
-		dirty = true;
+		{"ParaV", typGOBJ, &rib, 0L},
+		{"Arrows", typLAST | typOBJLST, &Arrows, &nArrows}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		c_flags = 0L;
+		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+		dirty = true;
 		if(name) {
-			sprintf(TmpTxt, "xyz-plot (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xyz-plot (%s)", name);
+#else
+			i = sprintf(TmpTxt, "xyz-plot (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		//now set parent in all children
-		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->parent = this;
-		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->parent = this;
-		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->parent = this;
-		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->parent = this;
-		if(Line) Line->parent = this;
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		//now set parent in all children
+		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->parent = this;
+		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->parent = this;
+		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->parent = this;
+		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->parent = this;
+		if(Line) Line->parent = this;
 		if(rib) rib->parent = this;
-		return true;
-	case FILE_WRITE:
+		return true;
+	case FILE_WRITE:
 		if(Line) Line->FileIO(rw);
-		if(rib) rib->FileIO(rw);
-		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->FileIO(rw);
-		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->FileIO(rw);
-		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
-		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Scatt3D", Desc);
-		}
-	return false;
-}
-
+		if(rib) rib->FileIO(rw);
+		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->FileIO(rw);
+		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->FileIO(rw);
+		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
+		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Scatt3D", Desc);
+		}
+	return false;
+}
+
 void
 Ribbon::RegGO(void *n)
 {
@@ -2795,48 +2993,52 @@ Ribbon::RegGO(void *n)
 		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
 		((notary*)n)->AddRegGO(this);
 		}
-}
-
-bool
-Ribbon::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"hide", typNZINT, &hidden, 0L},
-		{"z-pos", typNZLFLOAT, &z_value},
-		{"z-width", typNZLFLOAT, &z_width},
-		{"relwidth", typNZLFLOAT, &relwidth},
-		{"ssRefX", typTEXT, &ssRefX, 0L},
-		{"ssRefY", typTEXT, &ssRefY, 0L},
-		{"ssRefZ", typTEXT, &ssRefZ, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"Fill", typFILLDEF, &Fill, 0L},
-		{"values", typFPLST3D, &values, &nVal},
-		{"Planes", typLAST | typOBJLST, &planes, &nPlanes}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
-		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
-		relwidth = 0.6;				dirty = true;
-		if(name) {
-			sprintf(TmpTxt, "ribbon (%s)", name);
-			free(name);		name=strdup(TmpTxt);
-			}
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		//now set parent in all children
-		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Ribbon", Desc);
-		}
-	return false;
+}
+
+bool
+Ribbon::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
+		{"z-pos", typNZLFLOAT, &z_value},
+		{"z-width", typNZLFLOAT, &z_width},
+		{"relwidth", typNZLFLOAT, &relwidth},
+		{"ssRefX", typTEXT, &ssRefX, 0L},
+		{"ssRefY", typTEXT, &ssRefY, 0L},
+		{"ssRefZ", typTEXT, &ssRefZ, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"values", typFPLST3D, &values, &nVal},
+		{"Planes", typLAST | typOBJLST, &planes, &nPlanes}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+		relwidth = 0.6;				dirty = true;
+		if(name) {
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "ribbon (%s)", name);
+#else
+			i = sprintf(TmpTxt, "ribbon (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
+			}
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		//now set parent in all children
+		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Ribbon", Desc);
+		}
+	return false;
 }
 
 void
@@ -2872,8 +3074,12 @@ Grid3D::FileIO(int rw)
 		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
 		step.fx = step.fz = 1.0;
 		if(name) {
-			sprintf(TmpTxt, "grid (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "grid (%s)", name);
+#else
+			i = sprintf(TmpTxt, "grid (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
 		return true;
 	case FILE_READ:
@@ -2888,28 +3094,33 @@ Grid3D::FileIO(int rw)
 		return ExecOutput(Notary->RegisterGO(this), "Grid3D", Desc);
 		}
 	return false;
-}
-
-bool
-Limits::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Bounds", typLAST | typFRECT, &Bounds, 0L}};
-
-	switch(rw) {
-	case INIT_VARS:
+}
+
+bool
+Limits::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Bounds", typLAST | typFRECT, &Bounds, 0L}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
 		if(name) {
-			sprintf(TmpTxt, "limits (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "limits (%s)", name);
+#else
+			i = sprintf(TmpTxt, "limits (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), "Limits", Desc);
-		}
-	return false;
-}
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "Limits", Desc);
+		}
+	return false;
+}
 
 void
 Function::RegGO(void *n)
@@ -2919,43 +3130,49 @@ Function::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Function::FileIO(int rw)
-{
-	descIO Desc[] = {
+
+bool
+Function::FileIO(int rw)
+{
+	descIO Desc[] = {
 		{"hide", typNZINT, &hidden, 0L},
-		{"x1", typNZLFLOAT, &x1, 0L},
-		{"x2", typNZLFLOAT, &x2, 0L},
-		{"xstep", typNZLFLOAT, &xstep, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"f_xy", typTEXT, &cmdxy, 0L},
-		{"param", typTEXT, &param, 0L},
-		{"DataLine", typLAST | typGOBJ, &dl, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		cmdxy = param = 0L;
-		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
+		{"x1", typNZLFLOAT, &x1, 0L},
+		{"x2", typNZLFLOAT, &x2, 0L},
+		{"xstep", typNZLFLOAT, &xstep, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"f_xy", typTEXT, &cmdxy, 0L},
+		{"param", typTEXT, &param, 0L},
+		{"DataLine", typGOBJ, &dl, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
+	int i;
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		cmdxy = param = 0L;
+		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
 		if(name) {
-			sprintf(TmpTxt, "function (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "function (%s)", name);
+#else
+			i = sprintf(TmpTxt, "function (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		if(dl) dl->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(dl) dl->FileIO(rw);
-		ExecOutput(Notary->RegisterGO(this), "Function", Desc);
-		}
-	return false;
-}
-
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(dl) dl->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(dl) dl->FileIO(rw);
+		ExecOutput(Notary->RegisterGO(this), "Function", Desc);
+		}
+	return false;
+}
+
 void
 FitFunc::RegGO(void *n)
 {
@@ -2966,77 +3183,81 @@ FitFunc::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-FitFunc::FileIO(int rw)
-{
-	descIO Desc[] = {
+
+bool
+FitFunc::FileIO(int rw)
+{
+	descIO Desc[] = {
 		{"hide", typNZINT, &hidden, 0L},
-		{"ssXref", typTEXT, &ssXref, 0L},
-		{"ssYref", typTEXT, &ssYref, 0L},
-		{"x1", typNZLFLOAT, &x1, 0L},
-		{"x2", typNZLFLOAT, &x2, 0L},
-		{"xstep", typNZLFLOAT, &xstep, 0L},
-		{"conv", typNZLFLOAT, &conv, 0L},
+		{"ssXref", typTEXT, &ssXref, 0L},
+		{"ssYref", typTEXT, &ssYref, 0L},
+		{"x1", typNZLFLOAT, &x1, 0L},
+		{"x2", typNZLFLOAT, &x2, 0L},
+		{"xstep", typNZLFLOAT, &xstep, 0L},
+		{"conv", typNZLFLOAT, &conv, 0L},
 		{"chi2", typNZLFLOAT, &chi2, 0L},
-		{"maxiter", typNZINT, &maxiter, 0L},
-		{"Line", typLINEDEF, &Line, 0L},
-		{"f_xy", typTEXT, &cmdxy, 0L},
+		{"maxiter", typNZINT, &maxiter, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"f_xy", typTEXT, &cmdxy, 0L},
 		{"p_xy", typTEXT, &parxy, 0L},
-		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
-	int i;
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		cmdxy = parxy = 0L;
-		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
-		conv = 1.0e-15;	maxiter = 100;
-		dl = 0L;
+		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
+	int i;
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		cmdxy = parxy = 0L;
+		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
+		conv = 1.0e-15;	maxiter = 100;
+		dl = 0L;
 		if(name) {
-			sprintf(TmpTxt, "fit function (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "fit function (%s)", name);
+#else
+			i = sprintf(TmpTxt, "fit function (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		if(Symbols) for(i = 0; i < nPoints; i++)
-			if(Symbols[i]) Symbols[i]->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "FitFunc", Desc);
-		}
-	return false;
-}
-
-bool
-GridLine::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"Line", typLINEDEF, &LineDef, 0L},
-		{"flags", typLAST | typDWORD, &flags, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		return SaveVarGO(Desc);
-	case INIT_VARS:
-		InitVarsGO(Desc);
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(Symbols) for(i = 0; i < nPoints; i++)
+			if(Symbols[i]) Symbols[i]->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "FitFunc", Desc);
+		}
+	return false;
+}
+
+bool
+GridLine::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"flags", typLAST | typDWORD, &flags, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		InitVarsGO(Desc);
 		ncpts = 0;		cpts = 0L;	gl1 = gl2 = gl3 = 0L;	ls = 0L;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;	mo = 0L;
-		return true;
-	case FILE_READ:
-		return ExecInput(Desc);
-	case FILE_WRITE:
-		return ExecOutput(Notary->RegisterGO(this), 
-			Id == GO_GRIDLINE ?(char*)"GridLine" : 
-			Id == GO_GRIDRADIAL? (char*)"GridRadial" : (char*)"GridLine3D", Desc);
-		}
-	return false;
-}
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;	mo = 0L;
+		return true;
+	case FILE_READ:
+		return ExecInput(Desc);
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), 
+			Id == GO_GRIDLINE ?(char*)"GridLine" : 
+			Id == GO_GRIDRADIAL? (char*)"GridRadial" : (char*)"GridLine3D", Desc);
+		}
+	return false;
+}
 
 void
 Tick::RegGO(void *n)
@@ -3047,95 +3268,99 @@ Tick::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Tick::FileIO(int rw)
-{
-	GraphObj *gl = Grid;
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"Val", typLFLOAT, &value, 0L},
-		{"Flags", typDWORD, &flags, 0L},
-		{"Rot", typNZLFLOAT, &angle, 0L},
-		{"GridType", typINT, &gl_type, 0L},
-		{"Grid", typGOBJ, &gl, 0L},
-		{"Label", typGOBJ, &label, 0L},
-		{"Size", typLAST | typLFLOAT, &size, 0L}};
-
-	switch(rw) {
-	case SAVE_VARS:
-		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
-		if(label) label->FileIO(rw);
-		return SaveVarGO(Desc);
-	case INIT_VARS:
+
+bool
+Tick::FileIO(int rw)
+{
+	GraphObj *gl = Grid;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"Val", typLFLOAT, &value, 0L},
+		{"Flags", typDWORD, &flags, 0L},
+		{"Rot", typNZLFLOAT, &angle, 0L},
+		{"GridType", typINT, &gl_type, 0L},
+		{"Grid", typGOBJ, &gl, 0L},
+		{"Label", typGOBJ, &label, 0L},
+		{"Size", typLAST | typLFLOAT, &size, 0L}};
+
+	switch(rw) {
+	case SAVE_VARS:
+		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+		if(label) label->FileIO(rw);
+		return SaveVarGO(Desc);
+	case INIT_VARS:
 		InitVarsGO(Desc);
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		fix = fiy = 0.0f;	ls = 0L;	Grid = 0L;	mo = 0L;
-		size = defs.GetSize(SIZE_AXIS_TICKS);
-		return true;
-	case FILE_READ:
-		ExecInput(Desc);
-		Grid = (GridLine*) gl;
-		if(Grid)Grid->parent = this;
-		if(label)label->parent = this;
-		return true;
-	case FILE_WRITE:
-		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
-		else gl = 0L;
-		if(label) label->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Tick", Desc);
-		}
-	return false;
-}
-
-void
-Axis::TickFile(char *name)
-{
-	ReadCache *ca;
-	int i, j, k, nt;
-	char line[500], item[20];
-	Tick **ttck;
-
-	if(!name) return;
-	if(!(ca = new ReadCache())) return;
-	if(! ca->Open(name)) {
-		delete ca;
-		sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
-		ErrorBox(TmpTxt);
-		return;
-		}
-	Command(CMD_FLUSH, 0L, 0L);
-	if(!(Ticks = ((Tick**)calloc(nt = 100, sizeof(Tick*))))) return;
-	for(i = 0; ; i++) {
-		j = k = 0;
-		ca->ReadLine(line, sizeof(line));
-		if(!line[0]) break;
-		while(line[j] && line[j] < 33) j++;
-		do{ item[k] = line[j++]; }
-			while(item[k] >32 && item[k++] != '=' && k <sizeof(item) && j <sizeof(line));
-		item[k--] = 0;		if(!line[j-1])j--;
-		while(k && !(isdigit(item[k])))item[k--]=0;
-		while(line[j] && (line[j]<33 || line[j] == '"'))j++;
-		k = strlen(line);
-		while(k >=j && (line[k] < 33 || line[k] == '"')) line[k--] = 0;
-		//realloc table if necessary
-		if(NumTicks >= nt) {
-			if((ttck= (Tick**)realloc(Ticks, (nt += 1000)*sizeof(Tick*))))Ticks= ttck;
-			else NumTicks--;
-			}
-		//now add tick to table
-		if(!(Ticks[NumTicks] = new Tick(this, data, atof(item),
-			line[j] ? axis->flags : axis->flags | AXIS_MINORTICK)))break;
-		Ticks[NumTicks]->Command(CMD_SETTEXT, line+j, 0L);
-		NumTicks++;
-		}
-	ca->Close();
-	if(!NumTicks && Ticks) {
-		free(Ticks);
-		NumTicks = 0;
-		}
-	delete ca;
-}
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		fix = fiy = 0.0f;	ls = 0L;	Grid = 0L;	mo = 0L;
+		size = DefSize(SIZE_AXIS_TICKS);
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		Grid = (GridLine*) gl;
+		if(Grid)Grid->parent = this;
+		if(label)label->parent = this;
+		return true;
+	case FILE_WRITE:
+		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+		else gl = 0L;
+		if(label) label->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Tick", Desc);
+		}
+	return false;
+}
+
+void
+Axis::TickFile(char *name)
+{
+	ReadCache *ca;
+	int i, j, k, nt;
+	char line[500], item[20];
+	Tick **ttck;
+
+	if(!name) return;
+	if(!(ca = new ReadCache())) return;
+	if(! ca->Open(name)) {
+		delete ca;
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "Error open file \"%s\"\nfor axis ticks", name);
+#else
+		sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
+#endif
+		ErrorBox(TmpTxt);
+		return;
+		}
+	Command(CMD_FLUSH, 0L, 0L);
+	if(!(Ticks = ((Tick**)calloc(nt = 100, sizeof(Tick*))))) return;
+	for(i = 0; ; i++) {
+		j = k = 0;
+		ca->ReadLine(line, sizeof(line));
+		if(!line[0]) break;
+		while(line[j] && line[j] < 33) j++;
+		do{ item[k] = line[j++]; }
+			while(item[k] >32 && item[k++] != '=' && k <sizeof(item) && j <sizeof(line));
+		item[k--] = 0;		if(!line[j-1])j--;
+		while(k && !(isdigit(item[k])))item[k--]=0;
+		while(line[j] && (line[j]<33 || line[j] == '"'))j++;
+		k = (int)strlen(line);
+		while(k >=j && (line[k] < 33 || line[k] == '"')) line[k--] = 0;
+		//realloc table if necessary
+		if(NumTicks >= nt) {
+			if((ttck= (Tick**)realloc(Ticks, (nt += 1000)*sizeof(Tick*))))Ticks= ttck;
+			else NumTicks--;
+			}
+		//now add tick to table
+		if(!(Ticks[NumTicks] = new Tick(this, data, atof(item),
+			line[j] ? axis->flags : axis->flags | AXIS_MINORTICK)))break;
+		Ticks[NumTicks]->Command(CMD_SETTEXT, line+j, 0L);
+		NumTicks++;
+		}
+	ca->Close();
+	if(!NumTicks && Ticks) {
+		free(Ticks);
+		NumTicks = 0;
+		}
+	delete ca;
+}
 
 void
 Axis::RegGO(void *n)
@@ -3148,83 +3373,83 @@ Axis::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Axis::FileIO(int rw)
-{
-	char *tickfile = 0L;
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"sAxLine", typLFLOAT, &sizAxLine, 0L},
-		{"sAxTick", typLFLOAT, &sizAxTick, 0L},
-		{"BrkGap", typLFLOAT, &brkgap, 0L},
-		{"BrkSymSize", typLFLOAT, &brksymsize, 0L},
-		{"BrkSym", typINT, &brksym, 0L},
-		{"sTickLabel", typLFLOAT, &sizAxTickLabel, 0L},
-		{"tick_type", typNZINT, &tick_type, 0L},
-		{"tick_angle", typNZLFLOAT, &tick_angle, 0L},
-		{"LbDist", typNZLFPOINT, &lbdist, 0L},
-		{"TickLbDist", typNZLFPOINT, &tlbdist, 0L}, 
-		{"Color", typDWORD, &colAxis, 0L},
-		{"AxisDef", typPTRAXDEF, &axis},
-		{"GridLine", typLINEDEF, &GridLine, 0L},
-		{"GridType", typINT, &gl_type, 0L},
-		{"Ticks", typOBJLST, &Ticks, (long*)&NumTicks},
-		{"Label", typGOBJ, &axisLabel, 0L},
-		{"TickFile", typTEXT, &tickfile, 0L},
-		{"ssRefTV", typTEXT, &ssMATval, 0L},
-		{"ssRefTL", typTEXT, &ssMATlbl, 0L},
-		{"ssRefMT", typTEXT, &ssMITval, 0L},
-		{"tlbDef", typLAST | typTXTDEF, &tlbdef, 0L}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		sizAxLine = defs.GetSize(SIZE_AXIS_LINE);
-		sizAxTick = defs.GetSize(SIZE_AXIS_TICKS);
-		sizAxTickLabel = defs.GetSize(SIZE_TICK_LABELS);
-		colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
-		GridLine.color = 0x00808080L;
-		GridLine.pattern = 0xf8f8f8f8L;
-		brksymsize = defs.GetSize(SIZE_TICK_LABELS);
-		brkgap = defs.GetSize(SIZE_AXIS_TICKS);
-		brksym = 2;
-		tlbdef.ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
-		tlbdef.ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
-		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
-		tlbdef.fSize = parent ? parent->GetSize(SIZE_TICK_LABELS) : defs.GetSize(SIZE_TICK_LABELS);
-		tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
-		tlbdef.Style = TXS_NORMAL;
-		tlbdef.Mode = TXM_TRANSPARENT;
-		tlbdef.Font = FONT_HELVETICA;
-		tlbdef.text = 0L;	l_segs = 0L;	nl_segs = 0;
-		drawOut = scaleOut = 0L;			bModified = false;
-		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
-		mo = 0L;
-		return true;
-	case FILE_READ:
-		if(axisLabel)DeleteGO(axisLabel);
-		if(tickfile) free(tickfile);		if(ssMATval) free(ssMATval);
-		if(ssMATlbl) free(ssMATlbl);		if(ssMITval) free(ssMITval);
-		tickfile = 0L;
-		if(ExecInput(Desc) && tickfile && tickfile[0]){
-			TickFile(tickfile);
-			free(tickfile);					tickfile = 0L;
-			}
-		if(axis) axis->owner = this;
-		if(axisLabel)axisLabel->parent = this;
-		if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->parent = this;
-		return true;
-	case FILE_WRITE:
-		//do all ticks
-		for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->FileIO(rw);
-		if(axisLabel) axisLabel->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Axis", Desc);
-		}
-	return false;
-}
-
+
+bool
+Axis::FileIO(int rw)
+{
+	char *tickfile = 0L;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"sAxLine", typLFLOAT, &sizAxLine, 0L},
+		{"sAxTick", typLFLOAT, &sizAxTick, 0L},
+		{"BrkGap", typLFLOAT, &brkgap, 0L},
+		{"BrkSymSize", typLFLOAT, &brksymsize, 0L},
+		{"BrkSym", typINT, &brksym, 0L},
+		{"sTickLabel", typLFLOAT, &sizAxTickLabel, 0L},
+		{"tick_type", typNZINT, &tick_type, 0L},
+		{"tick_angle", typNZLFLOAT, &tick_angle, 0L},
+		{"LbDist", typNZLFPOINT, &lbdist, 0L},
+		{"TickLbDist", typNZLFPOINT, &tlbdist, 0L}, 
+		{"Color", typDWORD, &colAxis, 0L},
+		{"AxisDef", typPTRAXDEF, &axis},
+		{"GridLine", typLINEDEF, &GridLine, 0L},
+		{"GridType", typINT, &gl_type, 0L},
+		{"Ticks", typOBJLST, &Ticks, (long*)&NumTicks},
+		{"Label", typGOBJ, &axisLabel, 0L},
+		{"TickFile", typTEXT, &tickfile, 0L},
+		{"ssRefTV", typTEXT, &ssMATval, 0L},
+		{"ssRefTL", typTEXT, &ssMATlbl, 0L},
+		{"ssRefMT", typTEXT, &ssMITval, 0L},
+		{"tlbDef", typLAST | typTXTDEF, &tlbdef, 0L}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		sizAxLine = DefSize(SIZE_AXIS_LINE);
+		sizAxTick = DefSize(SIZE_AXIS_TICKS);
+		sizAxTickLabel = DefSize(SIZE_TICK_LABELS);
+		colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+		GridLine.color = 0x00808080L;
+		GridLine.pattern = 0xf8f8f8f8L;
+		brksymsize = DefSize(SIZE_TICK_LABELS);
+		brkgap = DefSize(SIZE_AXIS_TICKS);
+		brksym = 2;
+		tlbdef.ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+		tlbdef.ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
+		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
+		tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
+		tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+		tlbdef.Style = TXS_NORMAL;
+		tlbdef.Mode = TXM_TRANSPARENT;
+		tlbdef.Font = FONT_HELVETICA;
+		tlbdef.text = 0L;	l_segs = 0L;	nl_segs = 0;
+		drawOut = scaleOut = 0L;			bModified = false;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+		mo = 0L;
+		return true;
+	case FILE_READ:
+		if(axisLabel)DeleteGO(axisLabel);
+		if(tickfile) free(tickfile);		if(ssMATval) free(ssMATval);
+		if(ssMATlbl) free(ssMATlbl);		if(ssMITval) free(ssMITval);
+		tickfile = 0L;
+		if(ExecInput(Desc) && tickfile && tickfile[0]){
+			TickFile(tickfile);
+			free(tickfile);					tickfile = 0L;
+			}
+		if(axis) axis->owner = this;
+		if(axisLabel)axisLabel->parent = this;
+		if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->parent = this;
+		return true;
+	case FILE_WRITE:
+		//do all ticks
+		for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->FileIO(rw);
+		if(axisLabel) axisLabel->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Axis", Desc);
+		}
+	return false;
+}
+
 void
 Plot3D::RegGO(void *n)
 {
@@ -3237,66 +3462,70 @@ Plot3D::RegGO(void *n)
 		}
 }
 
-bool
-Plot3D::FileIO(int rw)
-{
-	fPOINT3D rot_vec, rot_ang;
-	descIO Desc[] = {
-		{"xBounds", typLFPOINT, &xBounds, 0L},
-		{"yBounds", typLFPOINT, &yBounds, 0L},
-		{"zBounds", typLFPOINT, &zBounds, 0L},
-		{"Corner1", typPOINT3D, &cub1, 0L},
-		{"Corner2", typPOINT3D, &cub2, 0L},
-		{"Center", typPOINT3D, &rotC, 0L},
-		{"rot_vec", typPOINT3D, &rot_vec, 0L},
-		{"rot_ang", typPOINT3D, &rot_ang, 0L},
-		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
-		{"Plots", typLAST | typOBJLST, &plots, (long*)&nPlots}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);
-		drag = 0L;		moveable = 1;
-		//set up RotDef
-		RotDef[0] = 0.919384;		RotDef[1] = 0.389104;		RotDef[2] = -0.057709;
-		RotDef[3] = 0.327146;		RotDef[4] = 0.944974;		RotDef[5] = 1.0-RotDef[4];
-		cub1.fx = defs.GetSize(SIZE_GRECT_LEFT) + defs.GetSize(SIZE_DRECT_LEFT);
-		cub2.fx = defs.GetSize(SIZE_GRECT_LEFT) + defs.GetSize(SIZE_DRECT_RIGHT);
-		cub1.fy = defs.GetSize(SIZE_GRECT_TOP) + defs.GetSize(SIZE_DRECT_BOTTOM);
-		cub2.fy = defs.GetSize(SIZE_GRECT_TOP) + defs.GetSize(SIZE_DRECT_TOP);
-		cub1.fy += defs.GetSize(SIZE_DRECT_TOP);	cub2.fy += defs.GetSize(SIZE_DRECT_TOP);
-		cub1.fz = 0.0;
-		cub2.fz = defs.GetSize(SIZE_DRECT_BOTTOM) - defs.GetSize(SIZE_DRECT_TOP);
-		rotC.fx = (cub1.fx + cub2.fx)/2.0;		rotC.fy = (cub1.fy + cub2.fy)/2.0;
-		rotC.fz = (cub1.fz + cub2.fz)/2.0;
-		dispObs = 0L;		nmaxObs = 0;	crea_flags = 0L;		dirty = true;
-		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
-		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+bool
+Plot3D::FileIO(int rw)
+{
+	fPOINT3D rot_vec, rot_ang;
+	descIO Desc[] = {
+		{"xBounds", typLFPOINT, &xBounds, 0L},
+		{"yBounds", typLFPOINT, &yBounds, 0L},
+		{"zBounds", typLFPOINT, &zBounds, 0L},
+		{"Corner1", typPOINT3D, &cub1, 0L},
+		{"Corner2", typPOINT3D, &cub2, 0L},
+		{"Center", typPOINT3D, &rotC, 0L},
+		{"rot_vec", typPOINT3D, &rot_vec, 0L},
+		{"rot_ang", typPOINT3D, &rot_ang, 0L},
+		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
+		{"Plots", typLAST | typOBJLST, &plots, (long*)&nPlots}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		drag = 0L;		moveable = 1;
+		//set up RotDef
+		RotDef[0] = 0.919384;		RotDef[1] = 0.389104;		RotDef[2] = -0.057709;
+		RotDef[3] = 0.327146;		RotDef[4] = 0.944974;		RotDef[5] = 1.0-RotDef[4];
+		cub1.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_LEFT);
+		cub2.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_RIGHT);
+		cub1.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_BOTTOM);
+		cub2.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_TOP);
+		cub1.fy += DefSize(SIZE_DRECT_TOP);	cub2.fy += DefSize(SIZE_DRECT_TOP);
+		cub1.fz = 0.0;
+		cub2.fz = DefSize(SIZE_DRECT_BOTTOM) - DefSize(SIZE_DRECT_TOP);
+		rotC.fx = (cub1.fx + cub2.fx)/2.0;		rotC.fy = (cub1.fy + cub2.fy)/2.0;
+		rotC.fz = (cub1.fz + cub2.fz)/2.0;
+		dispObs = 0L;		nmaxObs = 0;	crea_flags = 0L;		dirty = true;
+		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
 		if(name) {
-			sprintf(TmpTxt, "3D-root (%s)", name);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D-root (%s)", name);
+#else
+			i = sprintf(TmpTxt, "3D-root (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
-		return true;
+		return true;
 	case FILE_READ:
 		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
 		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
-		ExecInput(Desc);
-		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
-		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
-		return true;
-	case FILE_WRITE:
-		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
-		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
-		//do all plots
-		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
-		//do all axes
-		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Plot3D", Desc);
-		}
-	return false;
-}
+		ExecInput(Desc);
+		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
+		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
+		return true;
+	case FILE_WRITE:
+		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
+		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
+		//do all plots
+		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
+		//do all axes
+		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Plot3D", Desc);
+		}
+	return false;
+}
 
 void
 Func3D::RegGO(void *n)
@@ -3339,16 +3568,20 @@ Func3D::FileIO(int rw)
 		z1 = -20.0;		z2 = 20.0;	zstep = 2.0;
 		gda = 0L;		gob = 0L;
 		param = cmdxy = 0L;
-		Line.width = defs.GetSize(SIZE_HAIRLINE);
-		Line.patlength = defs.GetSize(SIZE_PATLENGTH);
+		Line.width = DefSize(SIZE_HAIRLINE);
+		Line.patlength = DefSize(SIZE_PATLENGTH);
 		Line.color = Line.pattern = 0x0L;
 		Fill.color = 0x00c0c0c0;
 		Fill.color2 = 0x00ffffff;
 		Fill.hatch = 0L;
 		Fill.type = FILL_LIGHT3D;
 		if(name) {
-			sprintf(TmpTxt, "3D function (Plot %d)", cPlots);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D function (Plot %d)", cPlots);
+#else
+			i = sprintf(TmpTxt, "3D function (Plot %d)", cPlots);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
 		return true;
 	case FILE_READ:
@@ -3416,16 +3649,20 @@ FitFunc3D::FileIO(int rw)
 		gda = 0L;		gob = 0L;
 		conv = 1.0e-15;	maxiter = 100;
 		param = cmdxy = ssXref = ssYref = ssZref = 0L;
-		Line.width = defs.GetSize(SIZE_HAIRLINE);
-		Line.patlength = defs.GetSize(SIZE_PATLENGTH);
+		Line.width = DefSize(SIZE_HAIRLINE);
+		Line.patlength = DefSize(SIZE_PATLENGTH);
 		Line.color = Line.pattern = 0x0L;
 		Fill.color = 0x00c0c0c0;
 		Fill.color2 = 0x00ffffff;
 		Fill.hatch = 0L;
 		Fill.type = FILL_LIGHT3D;
 		if(name) {
-			sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
-			free(name);		name=strdup(TmpTxt);
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "FitFunc3D (Plot %d)", cPlots);
+#else
+			i = sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
 			}
 		return true;
 	case FILE_READ:
@@ -3446,7 +3683,7 @@ FitFunc3D::FileIO(int rw)
 		}
 	return false;
 }
-
+
 void
 Graph::RegGO(void *n)
 {
@@ -3459,77 +3696,78 @@ Graph::RegGO(void *n)
 		}
 }
 
-bool
-Graph::FileIO(int rw)
-{
-	int ixax, iyax;
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"Units", typNZINT, &units, 0L},
-		{"GRect", typFRECT, &GRect, 0L},
-		{"DRect", typFRECT, &DRect, 0L},
-		{"Bounds", typFRECT, &Bounds, 0L},
-		{"ColFrame", typDWORD, &ColGR, 0L},
-		{"ColFrameL", typDWORD, &ColGRL, 0L},
-		{"ColRec", typDWORD, &ColDR, 0L},
-		{"ColAxis", typDWORD, &ColAX, 0L},
-		{"Xaxis", typAXDEF, &x_axis, 0L},
-		{"Yaxis", typAXDEF, &y_axis, 0L},
-		{"DefXAxis", typINT, &ixax, 0L},
-		{"DefYAxis", typINT, &iyax, 0L},
-		{"Axes", typOBJLST, &Axes, (long*)&NumAxes},
-		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
-	int i;
-	bool bConvert = false;
-
-	ixax = iyax = -1;
-	switch(rw) {
-	case INIT_VARS:
-		InitVarsGO(Desc);			units = defs.cUnits = defs.dUnits;
-		OwnDisp = false;			dirty = true;
-		GRect.Ymin = defs.GetSize(SIZE_GRECT_TOP);		GRect.Ymax = defs.GetSize(SIZE_GRECT_BOTTOM);
-		GRect.Xmin = defs.GetSize(SIZE_GRECT_LEFT);		GRect.Xmax = defs.GetSize(SIZE_GRECT_RIGHT);
-		DRect.Ymin = defs.GetSize(SIZE_DRECT_TOP);		DRect.Ymax = defs.GetSize(SIZE_DRECT_BOTTOM);
-		DRect.Xmin = defs.GetSize(SIZE_DRECT_LEFT);		DRect.Xmax = defs.GetSize(SIZE_DRECT_RIGHT);
-		ColGR = defs.Color(COL_GRECT);					ColGRL = defs.Color(COL_GRECTLINE);
-		ColDR = defs.Color(COL_DRECT);					ColBG = defs.Color(COL_BG);
-		ColAX = defs.Color(COL_AXIS);
-		x_axis.max = y_axis.max = 1.0;					x_axis.owner = y_axis.owner = (void *)this;
-		rcDim.left = rcDim.right = rcDim.top = rcDim.bottom = 0;
-		rcUpd.left = rcUpd.right = rcUpd.top = rcUpd.bottom = 0;
-		CurrGO = 0L;		Disp = 0L;			Sc_Plots = 0L;
-		AxisTempl = 0;		nscp = 0;			CurrDisp = 0L;
+bool
+Graph::FileIO(int rw)
+{
+	int ixax, iyax;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"Units", typNZINT, &units, 0L},
+		{"Scale", typNZLFLOAT, &scale, 0L},
+		{"GRect", typFRECT, &GRect, 0L},
+		{"DRect", typFRECT, &DRect, 0L},
+		{"Bounds", typFRECT, &Bounds, 0L},
+		{"ColFrame", typDWORD, &ColGR, 0L},
+		{"ColFrameL", typDWORD, &ColGRL, 0L},
+		{"ColRec", typDWORD, &ColDR, 0L},
+		{"ColAxis", typDWORD, &ColAX, 0L},
+		{"Xaxis", typAXDEF, &x_axis, 0L},
+		{"Yaxis", typAXDEF, &y_axis, 0L},
+		{"DefXAxis", typINT, &ixax, 0L},
+		{"DefYAxis", typINT, &iyax, 0L},
+		{"Axes", typOBJLST, &Axes, (long*)&NumAxes},
+		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
+	int i;
+	bool bConvert = false;
+
+	ixax = iyax = -1;
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);			units = defs.cUnits = defs.dUnits;
+		OwnDisp = false;			dirty = true;
+		GRect.Ymin = defs.GetSize(SIZE_GRECT_TOP);		GRect.Ymax = defs.GetSize(SIZE_GRECT_BOTTOM);
+		GRect.Xmin = defs.GetSize(SIZE_GRECT_LEFT);		GRect.Xmax = defs.GetSize(SIZE_GRECT_RIGHT);
+		DRect.Ymin = defs.GetSize(SIZE_DRECT_TOP);		DRect.Ymax = defs.GetSize(SIZE_DRECT_BOTTOM);
+		DRect.Xmin = defs.GetSize(SIZE_DRECT_LEFT);		DRect.Xmax = defs.GetSize(SIZE_DRECT_RIGHT);
+		ColGR = defs.Color(COL_GRECT);					ColGRL = defs.Color(COL_GRECTLINE);
+		ColDR = defs.Color(COL_DRECT);					ColBG = defs.Color(COL_BG);
+		ColAX = defs.Color(COL_AXIS);
+		x_axis.max = y_axis.max = 1.0;					x_axis.owner = y_axis.owner = (void *)this;
+		rcDim.left = rcDim.right = rcDim.top = rcDim.bottom = 0;
+		rcUpd.left = rcUpd.right = rcUpd.top = rcUpd.bottom = 0;
+		CurrGO = 0L;		Disp = 0L;			Sc_Plots = 0L;
+		AxisTempl = 0;		nscp = 0;			CurrDisp = 0L;
 		ToolMode = TM_STANDARD;					zoom_def = 0L;
-		tl_pts = 0L;		tl_nPts = 0;		tickstyle = zoom_level = 0;
-		frm_g = frm_d = 0L;	PasteObj = 0L;		filename = 0L;
-		rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
-		return true;
-	case FILE_READ:
-		units = 0;			//default to mm if statement mising in file
-		if((bConvert =ExecInput(Desc)) && ixax>=0 && iyax >=0 && Axes && 
-			NumAxes >= ixax+1 && NumAxes >= iyax) {
-			if(Axes[ixax]) Axes[ixax]->Command(CMD_SET_AXDEF, &x_axis, 0L);
-			if(Axes[iyax]) Axes[iyax]->Command(CMD_SET_AXDEF, &y_axis, 0L);
-			return true;
-			}
-		return bConvert;
-	case FILE_WRITE:
-		bModified = false;
-		//find default axes
-		if(Axes) for(i = 0; Axes && i < NumAxes; i++) {
-			if(Axes[i] && Axes[i]->GetAxis() == &x_axis) ixax = i;
-			else if(Axes[i] && Axes[i]->GetAxis() == &y_axis) iyax = i;
+		tl_pts = 0L;		tl_nPts = 0;		tickstyle = zoom_level = 0;
+		frm_g = frm_d = 0L;	PasteObj = 0L;		filename = 0L;
+		rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
+		return true;
+	case FILE_READ:
+		units = 0;			//default to mm if statement mising in file
+		if((bConvert =ExecInput(Desc)) && ixax>=0 && iyax >=0 && Axes && 
+			NumAxes >= ixax+1 && NumAxes >= iyax) {
+			if(Axes[ixax]) Axes[ixax]->Command(CMD_SET_AXDEF, &x_axis, 0L);
+			if(Axes[iyax]) Axes[iyax]->Command(CMD_SET_AXDEF, &y_axis, 0L);
+			return true;
+			}
+		return bConvert;
+	case FILE_WRITE:
+		bModified = false;		if(scale == 1.0) scale = 0.0;
+		//find default axes
+		if(Axes) for(i = 0; Axes && i < NumAxes; i++) {
+			if(Axes[i] && Axes[i]->GetAxis() == &x_axis) ixax = i;
+			else if(Axes[i] && Axes[i]->GetAxis() == &y_axis) iyax = i;
 			}
-		if(Id == GO_GRAPH)RegGO(Notary);
-		//do all plots
-		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
-		//do all axes
-		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Graph", Desc);
-		}
-	return false;
-}
-
+		if(Id == GO_GRAPH)RegGO(Notary);
+		//do all plots
+		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+		//do all axes
+		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Graph", Desc);
+		}
+	return false;
+}
+
 void
 Page::RegGO(void *n)
 {
@@ -3541,75 +3779,79 @@ Page::RegGO(void *n)
 		((notary*)n)->AddRegGO(this);
 		}
 }
-
-bool
-Page::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"Type", typNZINT, &type, 0L},
-		{"Units", typNZINT, &units, 0L},
-		{"GRect", typFRECT, &GRect, 0L},
-		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
-	int i;
-
-	switch(rw) {
-	case INIT_VARS:
-		//assume that Graph::FileIO(INIT_VARS) has been executed
-		GRect.Xmin = GRect.Ymin = 0.0;
-		GetPaper(&GRect.Xmax, &GRect.Ymax);
-		ColBG = 0x00e8e8e8L;
-		LineDef.width = 0.0;	LineDef.patlength = 1.0;
-		LineDef.color = LineDef.pattern = 0x0L;
-		FillDef.type = FILL_NONE;
-		FillDef.color = 0x00ffffffL;	//use white paper
-		FillDef.scale = 1.0;
-		FillDef.hatch = 0L;		filename =0L;
-		return true;
-	case FILE_READ:
-		Graph::FileIO(rw);
-		return true;
-	case FILE_WRITE:
-		//do all plots
+
+bool
+Page::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"Units", typNZINT, &units, 0L},
+		{"GRect", typFRECT, &GRect, 0L},
+		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
+	int i;
+
+	switch(rw) {
+	case INIT_VARS:
+		//assume that Graph::FileIO(INIT_VARS) has been executed
+		GRect.Xmin = GRect.Ymin = 0.0;
+		GetPaper(&GRect.Xmax, &GRect.Ymax);
+		ColBG = 0x00e8e8e8L;
+		LineDef.width = 0.0;	LineDef.patlength = 1.0;
+		LineDef.color = LineDef.pattern = 0x0L;
+		FillDef.type = FILL_NONE;
+		FillDef.color = 0x00ffffffL;	//use white paper
+		FillDef.scale = 1.0;
+		FillDef.hatch = 0L;		filename =0L;
+		return true;
+	case FILE_READ:
+		Graph::FileIO(rw);
+		return true;
+	case FILE_WRITE:
+		//do all plots
 		bModified = false;
 		if(Id == GO_PAGE)RegGO(Notary);
-		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
-		return ExecOutput(Notary->RegisterGO(this), "Page", Desc);
-		}
-	return false;
-}
-
-bool
-DefsRW::FileIO(int rw)
-{
-	descIO Desc[] = {
-		{"dUnits", typINT, &defs.dUnits, 0L},
-		{"cUnits", typINT, &defs.dUnits, 0L},
+		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+		return ExecOutput(Notary->RegisterGO(this), "Page", Desc);
+		}
+	return false;
+}
+
+bool
+DefsRW::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"dUnits", typINT, &defs.dUnits, 0L},
+		{"cUnits", typINT, &defs.dUnits, 0L},
 		{"dtHeight", typINT, &dlgtxtheight, 0L},
 		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
 		{"fmt_date", typTEXT, &defs.fmt_date, 0L},
 		{"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
 		{"fmt_time", typTEXT, &defs.fmt_time, 0L},
-		{"curr_path", typTEXT, &defs.currPath, 0L},
-		{"File1", typTEXT, &defs.File1, 0L},
-		{"File2", typTEXT, &defs.File2, 0L},
-		{"File3", typTEXT, &defs.File3, 0L},
-		{"File4", typTEXT, &defs.File4, 0L},
-		{"File5", typTEXT, &defs.File5, 0L},
-		{"File6", typLAST | typTEXT, &defs.File6, 0L}};
-
-	switch(rw) {
-	case FILE_READ:
-		ExecInput(Desc);
-		return true;
-	case FILE_WRITE:
-		Notary = new notary();
-		unlink(defs.IniFile);
-		iFile = OpenOutputFile(defs.IniFile);
-		if(iFile >=0) {
-			ExecOutput(-1, "Defaults", Desc);
-			}
-		CloseOutputFile();	if(Notary) delete Notary;	Notary = 0L;
-		return true;
-		}
-	return false;
-}
+		{"curr_path", typTEXT, &defs.currPath, 0L},
+		{"File1", typTEXT, &defs.File1, 0L},
+		{"File2", typTEXT, &defs.File2, 0L},
+		{"File3", typTEXT, &defs.File3, 0L},
+		{"File4", typTEXT, &defs.File4, 0L},
+		{"File5", typTEXT, &defs.File5, 0L},
+		{"File6", typLAST | typTEXT, &defs.File6, 0L}};
+
+	switch(rw) {
+	case FILE_READ:
+		ExecInput(Desc);
+		return true;
+	case FILE_WRITE:
+		Notary = new notary();
+#ifdef USE_WIN_SECURE
+		_unlink(defs.IniFile);
+#else
+		unlink(defs.IniFile);
+#endif
+		iFile = OpenOutputFile(defs.IniFile);
+		if(iFile >=0) {
+			ExecOutput(-1, "Defaults", Desc);
+			}
+		CloseOutputFile();	if(Notary) delete Notary;	Notary = 0L;
+		return true;
+		}
+	return false;
+}
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index 14cd26f..6d64b7d 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -116,7 +116,7 @@ int ExecDrawOrderButt(GraphObj *parent, GraphObj *obj, int id)
 void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		void *data, int id)
 {
-	LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
 	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
 	POINT *pts;
 	int i, ix, iy, np;
@@ -245,7 +245,7 @@ void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 void OD_ErrBarTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		void *data, int id)
 {
-	LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
 	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
 	POINT pts[6];
 	int ix, iy;
@@ -309,7 +309,7 @@ void OD_ErrBarTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 void OD_WhiskerTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		void *data, int id)
 {
-	LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
 	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
 	POINT pts[6];
 	int ix, iy;
@@ -551,7 +551,7 @@ void OD_AxisDesc3D(int cmd, void *par, RECT *rec, anyOutput *o,
 void OD_BreakTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		void *data, int id)
 {
-	LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
 	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
 	POINT pts[15];
 	int i, ix, iy;
diff --git a/Output.cpp b/Output.cpp
index 6ee7048..82e3083 100755
--- a/Output.cpp
+++ b/Output.cpp
@@ -356,7 +356,6 @@ anyOutput::GetLine(LineDEF *lDef)
 	return false;
 }
 
-
 bool
 anyOutput::SetTextSpec(TextDEF *set)
 {
@@ -365,7 +364,6 @@ anyOutput::SetTextSpec(TextDEF *set)
 	return true;
 }
 
-
 bool
 anyOutput::ShowMark(void *src, int Mode)
 {
@@ -424,7 +422,7 @@ anyOutput::CalcCursorPos(char *txt, POINT p, POINT *fit)
 
 	d = TxtSet.iSize >>2;
 	if(!txt || !fit) return 0;
-	if (!(i = strlen(txt)))return 0;
+	if (!(i = (int)strlen(txt)))return 0;
 	//right justified text
 	if(TXA_HRIGHT == (TxtSet.Align & TXA_HRIGHT)){
 		if((p.x - fit->x) < d) return i;
@@ -455,7 +453,7 @@ anyOutput::TextCursor(char *txt, POINT p, POINT *fit, int *pos, int dx)
 	//recalculate caret position
 	if(txt && pos && !fit){
 		if(TxtSet.Align & TXA_HRIGHT) {		//right justfied text
-			if((i = strlen(txt)-(*pos))){
+			if((i = (int)strlen(txt)-(*pos))){
 				if(!oGetTextExtent(txt+(*pos), i, &w, &h)) return false;
 				w = p.x - w;
 				}
@@ -470,7 +468,7 @@ anyOutput::TextCursor(char *txt, POINT p, POINT *fit, int *pos, int dx)
 	else if(!fit)return false;
 	//right justified text: search caret and cursor position
 	else if(txt && (TxtSet.Align & TXA_HRIGHT)){
-		i = strlen(txt);
+		i = (int)strlen(txt);
 		if(i == CurrPos) w = 1;
 		else if(!oGetTextExtent(txt+CurrPos, i-CurrPos, &w, &h)) return false;
 		w = p.x - w;
@@ -638,7 +636,7 @@ anyOutput::oGetTextExtent(char *text, int cb, int *width, int *height)
 	case FONT_COURIER:		CharWidth = Cour_Char_Width;	break;
 	default:				CharWidth = Helv_Char_Width;	break;
 		}
-	if(!cb && text) cb = strlen(text);
+	if(!cb && text) cb = (int)strlen(text);
 	for(i = w = 0; i < cb; i++) w += CharWidth[text[i]];
 	*width = iround(((double)w * (double)TxtSet.iSize)/52.0);
 	*height = TxtSet.iSize;
@@ -676,7 +674,7 @@ anyOutput::oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 enum {HO_NONE, HO_RECT, HO_CIRCLE, HO_ELLIPSE, HO_BIGELLYPSE,
 	HO_POLYGON};
-struct {
+struct _HatchDef{
 	union {
 		struct {
 			RECT rec;
@@ -1768,7 +1766,7 @@ ExportTif::ExportTif(GraphObj *g, char *FileName, DWORD flags, double res, doubl
 			bmo->Erase(0x00ffffffL);
 			g->DoPlot(bmo);
 			}
-		name = strdup(FileName);
+		name = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 		}
 	oFile = 0;
 }
@@ -1820,24 +1818,40 @@ ExportTif::StartPage()
 		};
 	DWORD res_info[4] = {iround(hres), 0x01, iround(vres), 0x01};
 	char prog_name[20];
-
+	int cb;
 
 	if(name && bmo) {
+#ifdef USE_WIN_SECURE
+		if(_sopen_s(&oFile, name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 
+			0x40, S_IWRITE) || oFile < 0){
+			ErrorBox("Could not open output file");
+			return false;
+			}
+#else
 		if(-1 ==(oFile = open(name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
-			S_IWRITE | S_IREAD))) {
+			S_IWRITE | S_IREAD))){
 			ErrorBox("Could not open output file");
 			return false;
 			}
+#endif
 		*((int*)(header+30))= w;		*((int*)(header+42))= h;
 		*((DWORD*)(header+126)) = (DWORD)(w * h * 3);
 		*((int*)(header+90)) = sizeof(header) + sizeof(res_info) + 20;
 		*((int*)(header+138)) = sizeof(header);
 		*((int*)(header+150)) = sizeof(header)+8;
 		*((int*)(header+186)) = sizeof(header)+16;
-		sprintf(prog_name, "RLPlot %s", SZ_VERSION);
+		cb = rlp_strcpy(prog_name, 20, "RLPlot ");
+		rlp_strcpy(prog_name+cb, 20-cb, SZ_VERSION);
+#ifdef USE_WIN_SECURE
+		_write(oFile, &header, sizeof(header));
+		_write(oFile, &res_info, sizeof(res_info));
+		_write(oFile, &prog_name, 20);
+
+#else
 		write(oFile, &header, sizeof(header));
 		write(oFile, &res_info, sizeof(res_info));
-		write(oFile, &res_info, 20);
+		write(oFile, &prog_name, 20);
+#endif
 		return true;
 		}
 	return false;
@@ -1856,15 +1870,28 @@ ExportTif::EndPage()
 				bmo->oGetPix(j, i, &pix);			pix_data[c++] = cpix[0];
 				pix_data[c++] = cpix[1];			pix_data[c++] = cpix[2];
 				if(c >= 3072) {
+#ifdef USE_WIN_SECURE
+					_write(oFile, pix_data, 3072);
+#else
 					write(oFile, pix_data, 3072);
+#endif
 					c = 0;
 					}
 				}
 			}
+#ifdef USE_WIN_SECURE
+		_write(oFile, pix_data, c);
+#else
 		write(oFile, pix_data, c);
+#endif
 		free(pix_data);
 		}
-	oFile = close(oFile);
+#ifdef USE_WIN_SECURE
+	_close(oFile);
+#else
+	close(oFile);
+#endif
+	oFile = -1;
 	return true;
 }
 
diff --git a/PlotObs.cpp b/PlotObs.cpp
index 926bec2..8a7fe3a 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -43,12 +43,16 @@ int AxisTempl3D = 0;
 
 Plot::Plot(GraphObj *par, DataObj *d):GraphObj(par, d)
 {
+	int pos, nsize;
+
 	Id = GO_PLOT;
 	Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-	sprintf(TmpTxt, "Plot %d", ++cPlots);
-	name = strdup(TmpTxt);
-	use_xaxis = use_yaxis = 0;
-	hidden = 0;
+	if(name = (char*)malloc((nsize = 20)*sizeof(char))){
+		pos = rlp_strcpy(name, nsize, (char*)"Plot");
+		add_int_to_buff(&name, &pos, &nsize, ++cPlots, true, 0);
+		}
+	use_xaxis = use_yaxis = 0;	hidden = 0;
+	x_info = y_info = z_info = 0L;
 }
 
 double
@@ -70,8 +74,7 @@ Plot::GetSize(int select)
 	case SIZE_BARMINY:
 		return 1.0f;
 	default:
-		if(parent) return parent->GetSize(select);
-		else return defs.GetSize(select);
+		return DefSize(select);
 		}
 }
 
@@ -172,53 +175,52 @@ DataObj *
 Plot::CreaCumData(char *xr, char *yr, int mode, double base)
 {
 	char **yranges;
-	int i, j, nc, nr, ir, ic;
+	int i, j, nc, nr, ir, ic, n;
 	double value, old_val;
 	DataObj *CumData = 0L;
 	AccRange *ax = 0L, *ay = 0L;
 
 	if(!xr || !yr || !mode || !data) return 0L;
 	if(!(CumData = new DataObj()))return 0L;
+	//count valid data lines
 	if(!(ax = new AccRange(xr))) {
-		delete CumData;		return 0L;
+		delete CumData;		CumData = 0L;	return 0L;
 		}
-	nr = ax->CountItems();
+	for(nr = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); )
+		if(data->GetValue(ir, ic, &value))nr++;
 	if(!(yranges = split(yr, '&', &nc))){
 		delete CumData;		delete ax;		return 0L;
 		}
 	if(CumData->Init(mode == 1 || mode == 2 ? nr : nr * 2, nc+2)){
 		// set x values as first column
-		for(i = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++) {
-			if(data->GetValue(ir, ic, &value)) CumData->SetValue(i, 0, value);
-			CumData->SetValue(i, 1, base);
+		for(i = n = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++) {
+			if(data->GetValue(ir, ic, &value)){
+				CumData->SetValue(n, 0, value);			CumData->SetValue(n++, 1, base);
+				}
 			}
-		if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {	//complete polygon data
+		if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {			//complete polygon data
 			if(CumData->GetValue(nr-i, 0, &value)) CumData->SetValue(i-1+nr, 0, value);
 			}
 		//process all y-ranges
 		for (j = 2; j <= (nc+1); j++) if(ay = new AccRange(yranges[j-2])){
-			for(i = 0; i < nr; i++) {
-				if(CumData->GetValue(i, j-1, &value)) CumData->SetValue(i, j, value);
+			for(i = n = 0; i < nr; i++) {
+				if(CumData->GetValue(n, j-1, &value)) CumData->SetValue(n++, j, value);
 				}
-			for(i = 0, ay->GetFirst(&ic, &ir); ay->GetNext(&ic, &ir) && i < nr; i++) {
-				if(data->GetValue(ir, ic, &value) && CumData->GetValue(i, j, &old_val)){
+			for(i = n = 0, ay->GetFirst(&ic, &ir); ay->GetNext(&ic, &ir) && n < nr; i++) {
+				if(data->GetValue(ir, ic, &value) && CumData->GetValue(n, j, &old_val)){
 					switch (mode) {
 					case 1:	case 3:	value += old_val;			break;
 					case 2:	case 4: value = old_val -value;		break;
 						}
-					CumData->SetValue(i, j, value);
+					CumData->SetValue(n++, j, value);
 					}
 				}
-			if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {
-				//complete polygon data
+			if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {		//complete polygon data
 				if(CumData->GetValue(nr-i, j-1, &value)) CumData->SetValue(i-1+nr, j, value);
 				}
 			delete ay;		ay = 0L;
 			}
 		}
-
-
-
 	for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
 	if(ax) delete ax;	if(ay) delete ay;
 	free(yranges);
@@ -280,6 +282,8 @@ PlotScatt::~PlotScatt()
 {
 	ForEach(FE_FLUSH, 0L, 0L);
 	if(name) free(name);		name=0L;
+	if(x_info) free(x_info);	x_info = 0L;
+	if(y_info) free(x_info);	y_info = 0L;
 	Undo.InvalidGO(this);
 }
 
@@ -413,11 +417,11 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Symbols) {
 			if(TheLine && TheLine->Id == GO_DATALINE) {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i], 0L);
 				}
 			else {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
 				}
 			if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
 			}
@@ -472,7 +476,7 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 			((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
 			}
 		return true;
-	case CMD_HIDE_MARK:
+	case CMD_SCALE:			case CMD_HIDE_MARK:
 		return ForEach(cmd, tmpl, o);
 	case CMD_MUTATE:		case CMD_REPL_GO:
 		dirty = true;
@@ -566,9 +570,7 @@ PlotScatt::ForEach(int cmd, void *tmp, anyOutput *o)
 			}
 		if(TheLine) TheLine->parent = this;
 		return true;
-	case CMD_UPDATE:
-	case CMD_SET_DATAOBJ:
-	case CMD_AUTOSCALE:
+	case CMD_UPDATE:	case CMD_SET_DATAOBJ:	case CMD_AUTOSCALE:		case CMD_SCALE:
 		for(j = 0; j < 6; j++){
 			if(obs[j]) for(i = 0; i < nPoints; i++){
 				if(obs[j][i]) obs[j][i]->Command(cmd, tmp, o);
@@ -680,6 +682,8 @@ xyStat::~xyStat()
 	if(yRange) free(yRange);				yRange = 0L;
 	if(xRange) free(xRange);				xRange = 0L;
 	if(name) free(name);					name=0L;
+	if(x_info) free(x_info);				x_info = 0L;
+	if(y_info) free(x_info);				y_info = 0L;
 	Undo.InvalidGO(this);
 }
 
@@ -721,9 +725,9 @@ xyStat::CreateData()
 	lfPOINT *xy;
 	AccRange *rX, *rY;
 
-	if(curr_data) delete curr_data;			curr_data = 0L;
 	if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
 	if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
+	if(!x_info) x_info = rX->RangeDesc(data, 0);	if(!y_info) y_info = rY->RangeDesc(data, 0);
 	m = rX->CountItems();	n = 0;
 	if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
 		delete rX;	delete rY;
@@ -781,7 +785,7 @@ xyStat::CreateData()
 		else type &= (~0x0480);
 		}
 	else q1 = q2 = q3 = 0L;
-	if((curr_data = new DataObj()) && curr_data->Init(j, 6)) {
+	if((curr_data = curr_data ? curr_data : new DataObj()) && curr_data->Init(j, 6)) {
 		for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]);	// set x-values
 		for(i = 0; i < j; i++) {								// set y-values
 			if(ny[i] > 1) switch(type & 0x00f0) {
@@ -811,11 +815,11 @@ xyStat::CreateData()
 						curr_data->SetValue(i, 2, sqrt(ss));
 						break;
 					case 0x0200:
-						curr_data->SetValue(i, 2, sqrt(ss)/sqrt(ny[i]));
+						curr_data->SetValue(i, 2, sqrt(ss)/sqrt((double)ny[i]));
 						break;
 					case 0x1000:
 						d = distinv(t_dist, ny[i]-1, 1, 1.0-(ci/100.0), 2.0);
-						curr_data->SetValue(i, 2, d * sqrt(ss)/sqrt(ny[i]));
+						curr_data->SetValue(i, 2, d * sqrt(ss)/sqrt((double)ny[i]));
 						break;
 						}
 					}
@@ -839,14 +843,14 @@ xyStat::CreateData()
 				}
 			}
 		if(type & 0x6000) for(i = 0; i < j; i++) {				// number of cases
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#else
 			sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#endif
 			curr_data->SetText(i, 5, TmpTxt);
 			}
 		}
-	else {
-		if(curr_data) delete curr_data;
-		curr_data = 0L;
-		}
 	if(q1) free(q1);	if(q2) free(q2);	if(q3) free(q3);
 	for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
 	free(tay);	free(ay);	free(ax);	free(ny);	free(xy);
@@ -886,7 +890,8 @@ FreqDist::~FreqDist()
 		free(plots);						plots=0L;
 		}
 	if(name) free(name);					name=0L;
-
+	if(x_info) free(x_info);				x_info = 0L;
+	if(y_info) free(y_info);				y_info = 0L;
 }
 
 void
@@ -926,6 +931,9 @@ FreqDist::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			}
 		return false;
+	case CMD_SCALE:
+		if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->Command(cmd, tmpl, o);
+		return true;
 	case CMD_HIDE_MARK:
 		if(plots) for(i = 0; i < nPlots; i++) if(plots[i]){
 			if(tmpl == (void*)plots[i]) {
@@ -1012,28 +1020,37 @@ void
 FreqDist::ProcData(int sel)
 {
 	AccRange *ar;
-	int nv, i, j, r, c, ncl, *f_data, cb;
-	double min = HUGE_VAL, max = -HUGE_VAL, sum, mean, sd, tmp, *s_data, *t_data;
+	int nv, i, j, r, c, ncl, *f_data, cb_f, size_fo, pos_fo;
+	double dmin = HUGE_VAL, dmax = -HUGE_VAL, min, max, sum, mean, sd, tmp, *s_data, *t_data, lstep;
+	double chi2, df, x, y;
+	anyResult *result;
 	Bar **bars = 0L;
-	char *fo;
+	TextDEF td;
+	char *fo, *fdesc = 0L, formula[500];
 
 	if(!parent || !data || !ssRef || !plots) return;
 	if(curr_data) delete(curr_data);
 	if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
+		//copy spreadsheet data into array
 		nv = ar->CountItems();			ar->GetFirst(&c, &r);
 		if(!(s_data = (double*)malloc(nv * sizeof(double))) 
 			|| !(t_data = (double*)malloc(nv * sizeof(double)))) {
 			delete(ar);					return;
 			}
 		for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetValue(r, c, &tmp)) {
-			if(tmp > max) max = tmp;	if(tmp < min) min = tmp;
+			if(tmp > dmax) dmax = tmp;	if(tmp < dmin) dmin = tmp;
 			s_data[nv] = tmp;
 			switch (type & 0xff){
-			case 2:		t_data[nv] = log(tmp);	break;
+			case 2:
+				if(tmp > 0.0) t_data[nv] = log(tmp);
+				else nv--;
+				break;
 			default:	t_data[nv] = tmp;		break;
 				}
 			nv++;
 			}
+		min = dmin;		max = dmax;
+		lstep = (max-min)/100.0;
 		delete(ar);
 		d_variance(nv, t_data, &mean, &sd);
 		sd = sqrt(sd/((double)(nv-1)));
@@ -1057,14 +1074,17 @@ FreqDist::ProcData(int sel)
 			}
 		if(f_data[ncl]) ncl++;
 		curr_data->Init(ncl, 2);
+		//create data object containg the counts / bin and bars
 		for(i = 0; i< ncl; i++) {
 			curr_data->SetValue(i, 0, tmp = start + i * step + step * .5);
 			curr_data->SetValue(i, 1, (double)f_data[i]);
 			if(bars) {
-				bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i);
+				if(bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH,
+					0, i, 1, i, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
 				}
 			}
 		free(s_data);		free(t_data);		free(f_data);
+		//create bar chart
 		if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars))){
 			plots[0]->Command(CMD_BAR_FILL, &BarFill, 0L);
 			plots[0]->SetColor(COL_BAR_LINE, BarLine.color);
@@ -1074,22 +1094,128 @@ FreqDist::ProcData(int sel)
 			plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
 			plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
 			}
-		if((type & 0xff) && (fo = (char*)malloc(1000))) {
-			cb = sprintf(fo, "[1=Function]\n");
-			cb += sprintf(fo+cb,"x1= %g\n", min);
-			cb += sprintf(fo+cb,"x2= %g\n", max);
-			cb += sprintf(fo+cb,"xstep= %g\n", (max-min)/100.0);
-			cb += sprintf(fo+cb,"Line= 0.4 6 0x000000ff 0x0\n");
+		//create function
+		if((type & 0xff) && (fo = (char*)malloc(size_fo = 1000))) {
+			pos_fo = rlp_strcpy(fo, 1000, (char*) "[1=Function]\nx1=");
+			add_dbl_to_buff(&fo, &pos_fo, &size_fo, min, true);
+			add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nx2=", 4);
+			add_dbl_to_buff(&fo, &pos_fo, &size_fo, max, true);
+			add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nxstep=", 7);
+			add_dbl_to_buff(&fo, &pos_fo, &size_fo, lstep, true);
+			add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nLine=", 6);
+			add_dbl_to_buff(&fo, &pos_fo, &size_fo, DefSize(SIZE_DATA_LINE), true);
+			add_to_buff(&fo, &pos_fo, &size_fo,(char*)" 6 0x000000ff 0x0\n", 18);
+			cb_f = 0;
 			switch (type & 0xff){
-			case 2:
-				cb += sprintf(fo+cb,"f_xy=\"y=%g*lognormfreq(x,%g,%g)\"",nv*step, mean, sd);
+			case 2:				//lognormal
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
+#else
+				cb_f = sprintf(formula,"%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
+#endif
+				fdesc = (char*)"Desc=\"Lognormal Dist.\"\n";
+				break;
+			case 3:				//exponential
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*expfreq(x,%g)",nv*step, 1.0/mean);
+#else
+				cb_f = sprintf(formula,"%g*expfreq(x,%g)",nv*step, 1.0/mean);
+#endif
+				fdesc = (char*)"Desc=\"Exponential Dist.\"\n";
+				break;
+			case 4:				//rectangular
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
+#else
+				cb_f = sprintf(formula,"%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
+#endif
+				fdesc = (char*)"Desc=\"Rectangular Dist.\"\n";
+				break;
+			case 5:				//chi-square
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*chifreq(x,%g)",nv*step, mean);
+#else
+				cb_f = sprintf(formula,"%g*chifreq(x,%g)",nv*step, mean);
+#endif
+				fdesc = (char*)"Desc=\"Chi<sup>2</sup> Dist.\"\n";
 				break;
-			default:
-				cb += sprintf(fo+cb,"f_xy=\"y=%g*normfreq(x,%g,%g)\"",nv*step, mean, sd);
+			case 10:			//binomial
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
+#else
+				cb_f = sprintf(formula,"%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
+#endif
+				fdesc = (char*)"Desc=\"Binomial Dist.\"\n";
+				break;
+			case 11:			//poisson
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
+#else
+				cb_f = sprintf(formula,"%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
+#endif
+				fdesc = (char*)"Desc=\"Poisson Dist.\"\n";
+				break;
+			default:			//normal
+#ifdef USE_WIN_SECURE
+				cb_f = sprintf_s(formula, 500, "%g*normfreq(x,%g,%g)",nv*step, mean, sd);
+#else
+				cb_f = sprintf(formula,"%g*normfreq(x,%g,%g)",nv*step, mean, sd);
+#endif
+				fdesc = (char*)"Desc=\"Normal Dist.\"\n";
 				break;
 				}
+			if(cb_f) {
+				add_to_buff(&fo, &pos_fo, &size_fo, "f_xy=\"y=" , 8);
+				add_to_buff(&fo, &pos_fo, &size_fo, formula , cb_f);
+				add_to_buff(&fo, &pos_fo, &size_fo, "\\n\"\n" , 4);
+				}
+			if(fdesc)add_to_buff(&fo, &pos_fo, &size_fo, fdesc, 0);
 			OpenGraph(this, 0L, (unsigned char *)fo, false);
-			free(fo);
+			free(fo);							chi2 = df = 0.0;
+			//calculate chi-square test of fit
+			if(curr_data) for(i = 0; i< ncl; i++) {
+				if(curr_data->GetValue(i,0, &x) && curr_data->GetValue(i,1, &y)){
+#ifdef USE_WIN_SECURE
+					sprintf_s(TmpTxt, TMP_TXT_SIZE, "x=%g;%s", x, formula);
+#else
+					sprintf(TmpTxt, "x=%g;%s", x, formula);
+#endif
+					result = do_formula(curr_data, TmpTxt);
+					if(result->type == ET_VALUE && fabs(result->value) > 0.0) {
+						tmp = y-result->value;	
+						tmp = (tmp*tmp)/result->value;
+						chi2 += tmp;			df += 1.0;
+						}
+					}
+				}
+			//report result of the chi-square test
+			if(chi2 > 0.0 && parent && (fo = (char*)malloc(size_fo = 1000))) {
+				tmp = chi_dist(chi2, df-1.0, 1.0);
+				pos_fo = rlp_strcpy(fo, 1000, (char*)"chi<sup> 2</sup> =");
+				add_dbl_to_buff(&fo, &pos_fo, &size_fo, chi2, true);
+				add_to_buff(&fo, &pos_fo, &size_fo, (char*)", n =", 5);
+				add_dbl_to_buff(&fo, &pos_fo, &size_fo, df, true);
+				add_to_buff(&fo, &pos_fo, &size_fo, (char*)", df =", 6);
+				add_dbl_to_buff(&fo, &pos_fo, &size_fo, df-1.0, true);
+				add_to_buff(&fo, &pos_fo, &size_fo, (char*)", p =", 5);
+				if(tmp < 0.0001) {
+					pos_fo--;	add_to_buff(&fo, &pos_fo, &size_fo, (char*)"< 0.0001", 8);
+					}
+				else add_dbl_to_buff(&fo, &pos_fo, &size_fo, tmp, true);
+				if(!plots[2]) {
+					x = (parent->GetSize(SIZE_GRECT_RIGHT) - parent->GetSize(SIZE_GRECT_LEFT))/2.0;
+					y = parent->GetSize(SIZE_GRECT_BOTTOM) - DefSize(SIZE_TEXT)*5;
+					y -= parent->GetSize(SIZE_DRECT_TOP);
+					td.Align = TXA_VTOP | TXA_HCENTER;			td.ColBg = 0x00ffffffL;
+					td.ColTxt = 0x00ff0000L;					td.Font = FONT_HELVETICA;
+					td.fSize = DefSize(SIZE_TEXT);			td.iSize = 0;
+					td.Mode = TXM_TRANSPARENT;					td.RotBL = td.RotCHAR = 0.0;
+					td.Style = TXS_NORMAL;						td.text = 0L;
+					plots[2] = new Label(this, data, x, y, &td, 0x0L);
+					plots[2]->moveable = 1;
+					}
+				plots[2]->Command(CMD_SETTEXT, fo, 0L);			free(fo);
+				}
 			}
 		}
 }
@@ -1204,9 +1330,9 @@ Regression::Command(int cmd, void *tmpl, anyOutput *o)
 			ld = rLine->GetLine();
 			if(Symbols) {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i], "Regression");
 				}
-			else ((Legend*)tmpl)->HasFill(ld, 0L);
+			else ((Legend*)tmpl)->HasFill(ld, 0L, "Regression");
 			return true;
 			}
 		return false;
@@ -1254,6 +1380,9 @@ Regression::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Symbols) for (i = 0; i < nPoints; i++)
 			if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
 		return true;
+	case CMD_SCALE:
+		if(rLine) rLine->Command(cmd, tmpl, o);
+		if(sde) sde->Command(cmd, tmpl, o);
 	case CMD_SYMTEXT:		case CMD_SYM_RANGETEXT:
 	case CMD_SYMTEXTDEF:	case CMD_SYM_TYPE:
 		if(Symbols) for(i = 0; i < nPoints; i++)
@@ -1454,6 +1583,16 @@ BubblePlot::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Bubbles) for (i = 0; i < nPoints; i++)
 			if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
 		return true;
+	case CMD_SCALE:
+		if(!tmpl) return false;
+		BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		if(Bubbles) for(i = 0; i < nPoints; i++)
+			if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
+		return true;
 	case CMD_MRK_DIRTY:
 		dirty = true;
 	case CMD_SETSCROLL:		case CMD_REDRAW:
@@ -1560,7 +1699,7 @@ PolarPlot::GetSize(int select)
 	default:
 		if(parent) return parent->GetSize(select);
 		}
-	return defs.GetSize(select);
+	return DefSize(select);
 }
 
 void
@@ -1611,6 +1750,13 @@ PolarPlot::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_CONFIG:
 		Config();
 		return true;
+	case CMD_SCALE:
+		FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl, o);
+		return true;
 	case CMD_SET_DATAOBJ:
 		Id = GO_POLARPLOT;
 		data = (DataObj *)tmpl;	
@@ -1705,7 +1851,6 @@ BoxPlot::BoxPlot(GraphObj *par, DataObj *d):Plot(par, d)
 {
 	FileIO(INIT_VARS);
 	Id = GO_BOXPLOT;
-	if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
 }
 
 BoxPlot::BoxPlot(int src):Plot(0L, 0L)
@@ -1728,19 +1873,20 @@ BoxPlot::BoxPlot(int src):Plot(0L, 0L)
 		}
 }
 
-BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3):Plot(par, dt)
+BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3, char *box_name):Plot(par, dt)
 {
-	int i, nr;
+	int i, nr, cb;
 	lfPOINT fp;
 
-	FileIO(INIT_VARS);		Id = GO_BOXPLOT;	fp.fx = fp.fy = 0.0;
+	FileIO(INIT_VARS);		Id = GO_BOXPLOT;	fp.fx = fp.fy = 0.0;	cb = 0;
 	if(data && data->GetSize(&i, &nr)) {
-		nPoints = nr;
+		nPoints = nr;		if(box_name) cb = (int)strlen(box_name);
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
 		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		if(Boxes = (Box**)calloc(nr, sizeof(Box*))) for(i = 0; i < nr; i++) {
 			if(mode == 1) Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c1, i, c2, i, c1, i, c3, i);
 			else Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c2, i, c1, i, c3, i, c1, i);
+			if(box_name && box_name[0] && Boxes[i]) Boxes[i]->name = (char*)memdup(box_name, cb+1, 0);
 			}
 		}
 }
@@ -1887,11 +2033,11 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Symbols) {
 			if(TheLine && TheLine->Id == GO_DATALINE) {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i], 0L);
 				}
 			else {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
 				}
 			if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
 			}
@@ -1905,6 +2051,7 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 			CreateData();
 			return ForEach(CMD_SET_DATAOBJ, curr_data, o);
 			}
+	case CMD_SCALE:
 		return ForEach(cmd, tmpl, o);
 	case CMD_AUTOSCALE:
 		if(hidden) return false;
@@ -2142,26 +2289,26 @@ BoxPlot::CreateData()
 				curr_data->SetValue(i, 2, y - ss);	curr_data->SetValue(i, 3, y + ss);
 				}
 			else if((type & 0x00f0) == 0x0020) {
-				curr_data->SetValue(i, 2, y - ss/sqrt(ny[i]));	
-				curr_data->SetValue(i, 3, y + ss/sqrt(ny[i]));
+				curr_data->SetValue(i, 2, y - ss/sqrt((double)ny[i]));	
+				curr_data->SetValue(i, 3, y + ss/sqrt((double)ny[i]));
 				}
 			else if((type & 0x00f0) == 0x0050) {
 				d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_box/100.0), 2.0) : 0;
-				curr_data->SetValue(i, 2, y - d*ss/sqrt(ny[i]));	
-				curr_data->SetValue(i, 3, y + d*ss/sqrt(ny[i]));
+				curr_data->SetValue(i, 2, y - d*ss/(double)sqrt((double)ny[i]));	
+				curr_data->SetValue(i, 3, y + d*ss/(double)sqrt((double)ny[i]));
 				}
 			//Whisker info is in cols 4 & 5
 			if((type & 0x0f0f) == 0x0101) {
 				curr_data->SetValue(i, 4, y - ss);	curr_data->SetValue(i, 5, y + ss);
 				}
 			else if((type & 0x0f0f) == 0x0201) {
-				curr_data->SetValue(i, 4, y - ss/sqrt(ny[i]));
-				curr_data->SetValue(i, 5, y + ss/sqrt(ny[i]));
+				curr_data->SetValue(i, 4, y - ss/sqrt((double)ny[i]));
+				curr_data->SetValue(i, 5, y + ss/sqrt((double)ny[i]));
 				}
 			else if((type & 0x0f0f) == 0x0501) {
 				d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_err/100.0), 2.0) : 0;
-				curr_data->SetValue(i, 4, y - d*ss/sqrt(ny[i]));
-				curr_data->SetValue(i, 5, y + d*ss/sqrt(ny[i]));
+				curr_data->SetValue(i, 4, y - d*ss/sqrt((double)ny[i]));
+				curr_data->SetValue(i, 5, y + d*ss/sqrt((double)ny[i]));
 				}
 			}
 		if((type & 0x00f0) == 0x0040 || (type & 0x0f00) == 0x0400) for(i = 0; i < j; i++) {
@@ -2192,7 +2339,11 @@ BoxPlot::CreateData()
 		if(type & 0xc000) for(i = 0; i < j; i++) {
 			//labels ...
 			if((type & 0x4000) && curr_data->GetValue(i, 5, &y)) curr_data->SetValue(i, 6, y);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#else
 			sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#endif
 			curr_data->SetText(i, 7, TmpTxt);
 			}
 		}
@@ -2238,6 +2389,8 @@ DensDisp::~DensDisp()
 	if(yRange) free(yRange);		if(xRange) free(xRange);
 	yRange = xRange = 0L;
 	if(name) free(name);			name=0L;
+	if(x_info) free(x_info);		x_info = 0L;
+	if(y_info) free(y_info);		y_info = 0L;
 	Undo.InvalidGO(this);
 }
 
@@ -2302,6 +2455,14 @@ DensDisp::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SETSCROLL:		case CMD_REDRAW:
 		if(parent) return parent->Command(cmd, tmpl, o);
 		return false;
+	case CMD_SCALE:
+		DefLine.width *= ((scaleINFO*)tmpl)->sy.fy;		DefLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		DefFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;	DefFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		DefFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		for(i = 0; i < nPoints; i++){
+			if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+			}
+		return true;
 	case CMD_USEAXIS:
 		UseAxis(*((int*)tmpl));
 		return true;
@@ -2574,6 +2735,9 @@ StackBar::Command(int cmd, void *tmpl, anyOutput *o)
 		if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) 
 			((ObjTree*)tmpl)->Command(CMD_UPDATE, xyPlots[i], 0L);
 		return true;
+	case CMD_SCALE:
+		dspm.fx *= ((scaleINFO*)tmpl)->sx.fy;
+		dspm.fy *= ((scaleINFO*)tmpl)->sy.fy;
 	case CMD_LEGEND:
 		if(Boxes) for (i = 0; i < numPlots; i++)
 			if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
@@ -2773,6 +2937,10 @@ PieChart::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SET_DATAOBJ:
 		Id = GO_PIECHART;
 		data = (DataObj *)tmpl;
+	case CMD_SCALE:
+		if(cmd == CMD_SCALE) {
+			CtDef.fx *= ((scaleINFO*)tmpl)->sx.fy;	CtDef.fy *= ((scaleINFO*)tmpl)->sx.fy;
+			}
 	case CMD_SHIFT_OUT:		case CMD_SEG_FILL:		case CMD_SEG_LINE:
 	case CMD_SEG_MOVEABLE:	case CMD_LEGEND:
 		if(Segments) for(i = 0; i < nPts; i++)
@@ -3214,13 +3382,13 @@ Scatt3D::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Balls) {
 			if(Line && Line->Id == GO_LINE3D) {
 				for (i = 0; i < nBalls && i < 100; i++)
-					if(Balls[i]) ((Legend*)tmpl)->HasSym(&Line->Line, Balls[i]);
+					if(Balls[i]) ((Legend*)tmpl)->HasSym(&Line->Line, Balls[i], 0L);
 				}
 			else {
 				for (i = 0; i < nBalls && i < 100; i++) {
 					if(Balls[i]) {
 						if(Balls[i]->type) Balls[i]->Command(cmd, tmpl, o);
-						else ((Legend*)tmpl)->HasSym(0L, Balls[i]);
+						else ((Legend*)tmpl)->HasSym(0L, Balls[i], 0L);
 						}
 					}
 				}
@@ -3233,7 +3401,7 @@ Scatt3D::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SET_DATAOBJ:
 		Id = GO_SCATT3D;
 		data = (DataObj *)tmpl;
-	case CMD_UPDATE:
+	case CMD_UPDATE:	case CMD_SCALE:
 		if(Balls) {
 			SavVarObs((GraphObj**)Balls, nBalls, UNDO_CONTINUE);
 			for(i = 0; i < nBalls; i++)	if(Balls[i]) Balls[i]->Command(cmd, tmpl, o);
@@ -3328,16 +3496,19 @@ Ribbon::Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char
 	:Plot(par, d)
 {
 	FileIO(INIT_VARS);		Id = GO_RIBBON;		type = 1;
-	if(xr) ssRefX = strdup(xr);		if(yr) ssRefY = strdup(yr);
+	if(xr && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
+	if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
 	z_value = z;	z_width = width;
 }
 
-Ribbon::Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr)
+Ribbon::Ribbon(GraphObj *par, DataObj *d, int which, char *xr, char *yr, char *zr)
 	:Plot(par, d)
 {
-	FileIO(INIT_VARS);		Id = GO_RIBBON;		type = 2;
-	if(xr) ssRefX = strdup(xr);		if(yr) ssRefY = strdup(yr);
-	if(zr) ssRefZ = strdup(zr);
+	FileIO(INIT_VARS);		Id = GO_RIBBON;			type = which;
+	if(xr && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
+	if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
+	if(zr && zr[0]) ssRefZ = (char*)memdup(zr, (int)strlen(zr)+1, 0L);
+	CreateObs();
 }
 
 Ribbon::Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo)
@@ -3458,6 +3629,11 @@ Ribbon::Command(int cmd, void *tmpl, anyOutput *o)
 			break;
 			}
 		break;
+	case CMD_SCALE:
+		z_value *= ((scaleINFO*)tmpl)->sz.fy;
+		z_width *= ((scaleINFO*)tmpl)->sz.fy;
+		for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+		break;
 	case CMD_MRK_DIRTY:
 		dirty = true;
 	case CMD_SET_GO3D:		case CMD_SETSCROLL:		case CMD_REDRAW:
@@ -3509,10 +3685,11 @@ Ribbon::Command(int cmd, void *tmpl, anyOutput *o)
 void
 Ribbon::CreateObs()
 {
-	int i, rx, cx, ry, cy, rz, cz;
+	int i, j, n, rx, cx, ry, cy, rz, cz;
 	double fx, fy, fz, tmp;
 	fPOINT3D pg[5];
 	AccRange *rX, *rY, *rZ;
+	Triangle *trl, *trc, *trn;
 
 	if(planes || !data) return;
 	rX = rY = rZ = 0L;
@@ -3575,7 +3752,19 @@ Ribbon::CreateObs()
 			}
 		break;
 	case 3:
-		//external creation of planes;
+		if(!ssRefX || !ssRefY || !ssRefZ) break;
+		Undo.InvalidGO(this);
+		trl = Triangulate1(ssRefX, ssRefZ, ssRefY, data);
+		for(i = 0, trc = trl; trc; i++) trc = trc->next;
+		if((n = i) && (planes = (Plane3D**)malloc(n*sizeof(Plane3D*)))) 
+			for(i = nPlanes = 0, trc = trl; trc && i < n; i++) {
+			for(j = 0; j < 4; j++) {	//swap y and z values;
+				tmp = trc->pt[j].fz;	trc->pt[j].fz = trc->pt[j].fy;	trc->pt[j].fy = tmp;
+				}
+			planes[nPlanes++] = new Plane3D(this, data, trc->pt, 4);
+			trn = trc->next;	delete trc;		trc = trn;
+			}
+		dirty = true;			Command(CMD_AUTOSCALE, 0L, 0L);
 		break;
 		}
 	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
@@ -3589,7 +3778,7 @@ Ribbon::UpdateObs(bool bNewData)
 	AccRange *rX, *rY, *rZ;
 	int sel_id[] = {SIZE_XPOS, SIZE_YPOS, SIZE_ZPOS};
 
-	if(!planes || !values) return;
+	if(!planes || (!values && type < 3)) return;
 	rX = rY = rZ = 0L;
 	switch(type) {
 	case 1:
@@ -3649,6 +3838,12 @@ Ribbon::UpdateObs(bool bNewData)
 				}
 			}
 		break;
+	case 3:
+		if(planes) {
+			for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
+			free(planes);		planes = 0L;	nPlanes = 0;
+			}
+		CreateObs();
 		}
 	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
 }
@@ -3761,7 +3956,7 @@ Grid3D::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		break;
 	case CMD_LEGEND:
-		if(!hidden) ((Legend*)tmpl)->HasFill(&Line, planes ? &Fill : 0L);
+		if(!hidden) ((Legend*)tmpl)->HasFill(&Line, planes ? &Fill : 0L, 0L);
 		break;
 	case CMD_CONFIG:
 		return Configure();
@@ -3920,17 +4115,18 @@ Limits::Command(int cmd, void *tmpl, anyOutput *o)
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Calculate and display a user defined function
-Function::Function(GraphObj *par, DataObj *d):Plot(par, d)
+Function::Function(GraphObj *par, DataObj *d, char *desc):Plot(par, d)
 {
-	FileIO(INIT_VARS);
+	FileIO(INIT_VARS);		cmdxy = (char*)malloc(20*sizeof(char));
 	if(parent && parent->Id == GO_POLARPLOT) {
 		x1 = 0.0;			x2 = 360.0;			xstep = 0.5;
-		cmdxy = strdup("sin(pi*x/30)+1.1");
+		if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(pi*x/30)+1.1");
 		}
 	else {
 		x1 = 0.0;			x2 = 100.0;			xstep = 0.5;
-		cmdxy = strdup("sin(x)/x");
+		if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(x)/x");
 		}
+	if(desc) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
 	Id = GO_FUNCTION;
 }
 
@@ -3986,6 +4182,9 @@ Function::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
 	case CMD_DELOBJ:
 		if(parent && tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
 		break;
@@ -4005,15 +4204,15 @@ Function::Command(int cmd, void *tmpl, anyOutput *o)
 		return true;
 	case CMD_SETPARAM:
 		if(tmpl) {
-			if(param) free(param);
-			param = strdup((char*)tmpl);
+			if(param) free(param);			param = 0L;
+			if(*((char*)tmpl))param = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 			}
 		dirty = true;
 		return true;
 	case CMD_SETFUNC:
 		if(tmpl) {
-			if(cmdxy) free(cmdxy);
-			cmdxy = strdup((char*)tmpl);
+			if(cmdxy) free(cmdxy);			cmdxy = 0L;
+			if(*((char*)tmpl))cmdxy = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 			}
 		dirty = true;
 		return true;
@@ -4048,7 +4247,7 @@ Function::Update(anyOutput *o, DWORD flags)
 	if(!parent || !cmdxy) return false;
 	do_xyfunc(data, x1, x2, xstep, cmdxy, &xydata, &ndata, param);
 	if(xydata && ndata >1) {
-		if(!dl) dl = new DataLine(this, data, xydata, ndata);
+		if(!dl) dl = new DataLine(this, data, xydata, ndata, name);
 		else dl->LineData(xydata, ndata);
 		dirty = true;
 		Command(CMD_AUTOSCALE, 0L, 0L);
@@ -4062,9 +4261,10 @@ Function::Update(anyOutput *o, DWORD flags)
 FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
 {
 	FileIO(INIT_VARS);
-	x1 = 0.0;			x2 = 100.0;			xstep = 0.5;	dl = 0L;
-	cmdxy = strdup("a+b*x^c");
-	parxy = strdup("a=1; b=1; c=0.1;");
+	x1 = 0.0;			x2 = 100.0;				xstep = 0.5;	dl = 0L;
+	cmdxy = (char*)malloc(20*sizeof(char));		parxy = (char*)malloc(20*sizeof(char));
+	if(cmdxy) rlp_strcpy(cmdxy, 20, "a+b*x^c");
+	if(parxy) rlp_strcpy(parxy, 20, "a=1; b=1; c=0.1;");
 	Id = GO_FITFUNC;
 }
 
@@ -4132,7 +4332,7 @@ FitFunc::DoPlot(anyOutput *o)
 
 	if(!data || x1 >= x2) return;
 	dirty = false;
-	if(!dl && (dl = new Function(this, data))) {
+	if(!dl && (dl = new Function(this, data, "Fitted function"))) {
 		dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
 		dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
 		dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
@@ -4160,12 +4360,17 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 			ld = dl->GetLine();
 			if(Symbols) {
 				for (i = 0; i < nPoints && i < 100; i++)
-					if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i]);
+					if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i], "Fitted function");
 				}
-			else ((Legend*)tmpl)->HasFill(ld, 0L);
+			else ((Legend*)tmpl)->HasFill(ld, 0L, dl->name);
 			return true;
 			}
 		return false;
+	case CMD_SCALE:
+		if(dl) return dl->Command(cmd, tmpl, o);
+		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
 	case CMD_HIDE_MARK:
 		if(dl) return dl->Command(cmd, tmpl, o);
 		return false;
@@ -4183,7 +4388,7 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_AUTOSCALE:
 		if(dirty) {
-			if(!dl && (dl = new Function(this, data))) {
+			if(!dl && (dl = new Function(this, data, "Fitted function"))) {
 				dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
 				dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
 				dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
@@ -4204,7 +4409,7 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		Undo.String(this, &parxy, UNDO_CONTINUE);
 		do_fitfunc(data, ssXref, ssYref, 0L, &parxy, cmdxy, conv, maxiter, &chi2);
-		if(!dl) dl = new Function(this, data);
+		if(!dl) dl = new Function(this, data, "Fitted function");
 		if(dl){
 			dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
 			dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
@@ -4343,8 +4548,7 @@ Plot3D::GetSize(int select)
 	case SIZE_YCENTER:	return rotC.fy;
 	case SIZE_ZCENTER:	return rotC.fz;
 	default:
-		if(parent) return parent->GetSize(select);
-		else return defs.GetSize(select);
+		return DefSize(select);
 		}
 }
 
@@ -4441,6 +4645,17 @@ Plot3D::Command(int cmd, void *tmpl, anyOutput *o)
 	GraphObj **tmpPlots;
 
 	switch (cmd) {
+	case CMD_SCALE:
+		cub1.fx *= ((scaleINFO*)tmpl)->sx.fy;		cub1.fy *= ((scaleINFO*)tmpl)->sy.fy;
+		cub1.fz *= ((scaleINFO*)tmpl)->sz.fy;		cub2.fx *= ((scaleINFO*)tmpl)->sx.fy;
+		cub2.fy *= ((scaleINFO*)tmpl)->sy.fy;		cub2.fz *= ((scaleINFO*)tmpl)->sz.fy;
+		rotC.fx *= ((scaleINFO*)tmpl)->sx.fy;		rotC.fy *= ((scaleINFO*)tmpl)->sy.fy;
+		rotC.fz *= ((scaleINFO*)tmpl)->sz.fy;
+		if(plots) for(i = 0; i < nPlots; i++)
+			if(plots[i]) plots[i]->Command(cmd, tmpl, o);
+		if(Axes) for(i = 0; i < nAxes; i++)
+			if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+		return true;
 	case CMD_MOUSE_EVENT:
 		if(hidden || ((MouseEvent*)tmpl)->Action != MOUSE_LBUP || CurrGO) return false;
 		if(dispObs) for (i = nObs; i > 0; i--)	{
@@ -4649,24 +4864,24 @@ Plot3D::CreateAxes()
 		int txa;
 		}Axis3Ddef;
 	AxisDEF tmp_axis;
-	double ts = defs.GetSize(SIZE_AXIS_TICKS);
+	double ts = DefSize(SIZE_AXIS_TICKS);
 	int i;
 	if(Axes || !parent)return;
-	TextDEF tlbdef = {parent->GetColor(COL_AXIS), 0x00ffffffL, defs.GetSize(SIZE_TICK_LABELS),
+	TextDEF tlbdef = {parent->GetColor(COL_AXIS), 0x00ffffffL, DefSize(SIZE_TICK_LABELS),
 		0.0, 0.0, 0, TXA_HLEFT | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
 	Axis3Ddef *at = 0L;
 	Axis3Ddef at1[] = {
 		{cub1.fx, cub1.fy, 0.0, cub2.fx, cub1.fy, 0.0,
 			AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 1, 3,
-			0.0, NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*2.0), 0.0,
+			0.0, NiceValue((ts+DefSize(SIZE_AXIS_TICKS))*2.0), 0.0,
 			NiceValue(ts * 2.0), TXA_HCENTER | TXA_VTOP},
 		{cub1.fx, cub1.fy, 0.0, cub1.fx, cub2.fy, 0.0,
 			AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 2, 2,
-			-NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0), 0.0,
+			-NiceValue((ts+DefSize(SIZE_AXIS_TICKS))*3.0), 0.0,
 			-NiceValue(ts * 2.0), 0.0, TXA_HRIGHT | TXA_VCENTER},
 		{cub1.fx, cub1.fy, 0.0, cub1.fx, cub1.fy, cub2.fz,
 			AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 3, 2,
-			-NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0), 0.0,
+			-NiceValue((ts+DefSize(SIZE_AXIS_TICKS))*3.0), 0.0,
 			-NiceValue(ts * 2.0), 0.0, TXA_HRIGHT | TXA_VCENTER}};
 	Axis3Ddef at2[] = {
 		{at1[0].x1, at1[0].y1, at1[2].z2, at1[0].x2, at1[0].y2, at1[2].z2,
@@ -4915,6 +5130,8 @@ Plot3D::Rotate(double dx, double dy, double dz, anyOutput *o, bool accept)
 	double rotM[3][3], newM[3][3];			//rotation matrices
 	bool bRet = true;
 
+	o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+		Axes[1]->GetAxis(), Axes[2]->GetAxis());
 	for(i = 0; i < 3; i++) {
 		switch (i){
 		case 0:
@@ -5031,7 +5248,8 @@ Func3D::Func3D(GraphObj *par, DataObj *d)
 	:Plot3D(par, d, 0x0L)
 {
 	FileIO(INIT_VARS);
-	cmdxy = strdup("r=sqrt(x*x+z*z)\ny=1-exp(-8/(r+1))");
+	if(cmdxy = (char*)malloc(40*sizeof(char)))
+		rlp_strcpy(cmdxy, 40, (char*)"r=sqrt(x*x+z*z)\ny=1-exp(-8/(r+1))");
 	Id = GO_FUNC3D;
 }
 
@@ -5110,8 +5328,9 @@ FitFunc3D::FitFunc3D(GraphObj *par, DataObj *d)
 	:Plot3D(par, d, 0x0L)
 {
 	FileIO(INIT_VARS);
-	cmdxy = strdup("a+b*x^c");
-	param = strdup("a=1; b=1; c=0.1;");
+	cmdxy = (char*)malloc(20*sizeof(char));		param = (char*)malloc(20*sizeof(char));
+	if(cmdxy) rlp_strcpy(cmdxy, 20, (char*)"a+b*x^c");
+	if(param) rlp_strcpy(param, 20, (char*)"a=1; b=1; c=0.1;");
 	Id = GO_FITFUNC3D;
 }
 
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index d5df21c..68ceff3 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -68,9 +68,9 @@ Symbol::PropertyDlg()
 		{104, 105, 0, TOUCHEXIT, INCDECVAL1, &SymLine.width, 55, 37, 32, 10},
 		{105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 37, 20, 8},
 		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 5, 49, 45, 8},
-		{107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)SymLine.color, 55, 49, 25, 10},
+		{107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&SymLine.color, 55, 49, 25, 10},
 		{108, 109, 0, 0x0L, RTEXT, (void*)"fill color" , 5, 61, 45, 8},
-		{109, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)SymFill.color, 55, 61, 25, 10},
+		{109, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&SymFill.color, 55, 61, 25, 10},
 		{200, 204, 201, CHECKED | ISPARENT, GROUPBOX, (void*)" font ", 12, 28, 50, 45},
 		{201, 202, 0, TOUCHEXIT, RADIO1, (void*)"Helvetica", 15, 35, 45, 8},
 		{202, 203, 0, TOUCHEXIT, RADIO1, (void*)"Times", 15, 45, 45, 8},
@@ -114,9 +114,13 @@ Symbol::PropertyDlg()
 	lfPOINT o_pos, n_pos;
 
 	if(!parent) return false;
-	if(!Command(CMD_GETTEXT, (void*)text1, 0L)) sprintf(text1, "text");
+	if(!Command(CMD_GETTEXT, (void*)text1, 0L)) rlp_strcpy(text1, 40, "text");
+#ifdef USE_WIN_SECURE
+	if(data && data->GetSize(&width, &height)) sprintf_s(text2, 100, "b1:b%d", height);
+#else
 	if(data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
-	else sprintf(text2, "(not available)");
+#endif
+	else rlp_strcpy(text2, 100, "(not available)");
 	if((PrevSym = new Symbol(0L, data, 0.0f, 0.0f, type))){
 		PrevSym->SetColor(COL_SYM_LINE, SymLine.color);
 		PrevSym->SetColor(COL_SYM_FILL, SymFill.color);
@@ -129,7 +133,7 @@ Symbol::PropertyDlg()
 			PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
 		PrevSym->idx = idx;
 		}
-	if(PrevSym && (Dlg = new DlgRoot(SymDlg))) {
+	if(PrevSym && (Dlg = new DlgRoot(SymDlg, data))) {
 		Dlg->TextFont(201, FONT_HELVETICA);
 		Dlg->TextFont(202, FONT_TIMES);
 		Dlg->TextFont(203, FONT_COURIER);
@@ -148,8 +152,12 @@ Symbol::PropertyDlg()
 		if(textdef.Style & TXS_UNDERLINE) Dlg->SetCheck(207, 0L, true);
 		}
 	else return false;
-	if(parent->name) sprintf(TmpTxt, "Symbol of %s", parent->name);
-	else strcpy(TmpTxt, "Symbol properties");
+	if(parent->name) {
+		width = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol of ");
+		rlp_strcpy(TmpTxt+width, TMP_TXT_SIZE-width, parent->name);
+		width =10;
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol properties");
 	if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, 430, 260, Dlg, 0x0L)))return false;
 	tmpCol = 0x00c0c0c0L;	o_size = size;	o_lwidth = SymLine.width;
 	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lwidth);
@@ -165,7 +173,7 @@ Symbol::PropertyDlg()
 		case 1:
 			Undo.SetDisp(cdisp);
 			if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
-				Dlg->GetText(251, text1);
+				Dlg->GetText(251, text1, 40);
 				if(PrevSym->Command(CMD_GETTEXT, (void *)text2, 0L) && strcmp(text1, text2)) {
 					PrevSym->Command(CMD_SETTEXT, (void *)text1, 0L);
 					Dlg->DoPlot(NULL);
@@ -173,7 +181,7 @@ Symbol::PropertyDlg()
 					}
 				}
 			else if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
-				if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))	
+				if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
 					PrevSym->Command(CMD_RANGETEXT, &text2, 0L);
 				}
 			Dlg->GetValue(101, &n_size);		Dlg->GetValue(104, &n_lwidth);
@@ -205,8 +213,8 @@ Symbol::PropertyDlg()
 		case 252:										//use spreadsheet text
 			if(!data) Dlg->SetCheck(250, 0L, true);
 		case 250:										//use fixed text
-			if(Dlg->GetCheck(250) && Dlg->GetText(251,text1))PrevSym->Command(CMD_SETTEXT, text1, 0L);
-			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))	
+			if(Dlg->GetCheck(250) && Dlg->GetText(251,text1,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
 				PrevSym->Command(CMD_RANGETEXT, text2, 0L);
 			Dlg->DoPlot(NULL);
 			res = -1;
@@ -231,8 +239,8 @@ Symbol::PropertyDlg()
 			if(Dlg->GetValue(101, &tmpVal))	PrevSym->SetSize(SIZE_SYMBOL, tmpVal);
 			if(Dlg->GetValue(104, &tmpVal))	PrevSym->SetSize(SIZE_SYM_LINE, tmpVal);
 			if(PrevSym->type == SYM_TEXT) {
-				if(Dlg->GetCheck(250) && Dlg->GetText(251,text1))PrevSym->Command(CMD_SETTEXT, text1, 0L);
-				else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))	
+				if(Dlg->GetCheck(250) && Dlg->GetText(251,text1,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+				else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2,100))	
 					PrevSym->Command(CMD_RANGETEXT, text2, 0L);
 				}
 			Dlg->DoPlot(NULL);
@@ -270,7 +278,7 @@ Symbol::PropertyDlg()
 		if(PrevSym->type == SYM_TEXT) {
 			if(Dlg->GetCheck(250) && PrevSym->Command(CMD_GETTEXT, text1, 0L))
 				parent->Command(CMD_SYMTEXT_UNDO, text1, 0L);
-			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))	
+			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
 				parent->Command(CMD_SYM_RANGETEXT, text2, 0L);
 			if(PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L))
 				parent->Command(CMD_SYMTEXTDEF, &textdef, 0L);
@@ -286,45 +294,52 @@ Symbol::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Bubble properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BubDlg_DlgTmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,1,130,10,60,12\n"
+	"2,3,,,PUSHBUTTON,2,130,25,60,12\n"
+	"3,4,,,PUSHBUTTON,-2,130,40,60,12\n"
+	"4,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,120,100\n"
+	"6,7,200,ISPARENT,SHEET,4,5,10,120,100\n"
+	"7,,300,ISPARENT,SHEET,5,5,10,120,100\n"
+	"100,109,,NOSELECT,ODBUTTON,6,18,57,90,50\n"
+	"109,110,,,SYMRADIO,7,30,30,20,20\n"
+	"110,111,,,SYMRADIO,8,50,30,20,20\n"
+	"111,112,,,SYMRADIO,9,70,30,20,20\n"
+	"112,,,,SYMRADIO,10,90,30,20,20\n"
+	"200,201,,,LTEXT,11,10,30,110,8\n"
+	"201,202,210, ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"202,203,,,LTEXT,12,10,64,110,8\n"
+	"203,, 220,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"210,211,,,RADIO1,-3,40,38,45,8\n"
+	"211,212,,,RADIO1,13,40,46,45,8\n"
+	"212,,,,RADIO1,14,40,54,45,8\n"
+	"220,221,,,RADIO1,15,40,72,45,8\n"
+	"221,222,,,RADIO1,16,40,80,45,8\n"
+	"222,0,,,RADIO1,17,40,88,45,8\n"
+	"300,301,,,RTEXT,-12,10,40,45,8\n"
+	"301,302,,,EDVAL1,18,60,40,35,10\n"
+	"302,303,,,RTEXT,-13,10,60,45,8\n"
+	"303,304,,,EDVAL1,19,60,60,35,10\n"
+	"304,305,,,RTEXT,20,10,80,45,8\n"
+	"305,,,LASTOBJ, EDVAL1,21,60,80,35,10";
+
 bool
 Bubble::PropertyDlg()
 {
-	TabSHEET tab1 = {0, 50, 10, "Shape & Color"};
-	TabSHEET tab2 = {50, 90, 10, "Scaling"};
-	TabSHEET tab3 = {90, 120, 10, "Edit"};
+	TabSHEET tab1 = {0, 52, 10, "Shape & Color"};
+	TabSHEET tab2 = {52, 84, 10, "Scaling"};
+	TabSHEET tab3 = {84, 106, 10, "Edit"};
 	int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
-	DlgInfo BubDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BUBBLE", 130, 10, 60, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 60, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 60, 12},
-		{4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 100},
-		{6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 100},
-		{7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 100},
-		{100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 18, 57, 90, 50},
-		{109, 110, 0, 0x0L, SYMRADIO, (void *)&syms[0], 30, 30, 20, 20},
-		{110, 111, 0, 0x0L, SYMRADIO, (void *)&syms[1], 50, 30, 20, 20},
-		{111, 112, 0, 0x0L, SYMRADIO, (void *)&syms[2], 70, 30, 20, 20},
-		{112, 0, 0, 0x0L, SYMRADIO, (void *)&syms[3], 90, 30, 20, 20},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"Sizes are given as", 10, 30, 110, 8},
-		{201, 202, 210, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
-		{202, 203, 0, 0x0L, LTEXT, (void*)"Proportionality (relative to circle)", 10, 64, 110, 8},
-		{203, 0, 220, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
-		{210, 211, 0, 0x0L, RADIO1, (void *) Units[defs.cUnits].display, 40, 38, 45, 8},
-		{211, 212, 0, 0x0L, RADIO1, (void*)"scaling with X axis", 40, 46, 45, 8},
-		{212, 0, 0, 0x0L, RADIO1, (void*)"scaling with Y axis", 40, 54, 45, 8},
-		{220, 221, 0, 0x0L, RADIO1, (void*)"diameter", 40, 72, 45, 8},
-		{221, 222, 0, 0x0L, RADIO1, (void*)"circumference", 40, 80, 45, 8},
-		{222, 0, 0, 0x0L, RADIO1, (void*)"area", 40, 88, 45, 8},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 40, 45, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 60, 40, 35, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 60, 45, 8},
-		{303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 60, 60, 35, 10},
-		{304, 305, 0, 0x0L, RTEXT, (void*)"size", 10, 80, 45, 8},
-		{305, 0, 0, LASTOBJ, EDVAL1, &fs, 60, 80, 35, 10}};
+	void *dyndata[] = {(void*)"Apply to BUBBLE", (void*)"Apply to PLOT", (void*)&tab1, (void*)&tab2,
+		(void*)&tab3, (void*)&OD_filldef, (void *)&syms[0], (void *)&syms[1], (void *)&syms[2], (void *)&syms[3],
+		(void*)"Sizes are given as", (void*)"Proportionality (relative to circle)", (void*)"scaling with X axis",
+		(void*)"scaling with Y axis", (void*)"diameter", (void*)"circumference", (void*)"area", (void*)&fPos.fx,
+		(void*)&fPos.fy, (void*)"size", (void*)&fs};
+	DlgInfo *BubDlg = CompileDialog(BubDlg_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType;
+	int cb, res, tmpType;
 	lfPOINT o_pos, n_pos;
 	LineDEF newLine, newFillLine;
 	FillDEF newFill;
@@ -336,7 +351,7 @@ Bubble::PropertyDlg()
 	if(!parent) return false;
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BubbleLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BubbleFill, 0);
-	Dlg = new DlgRoot(BubDlg);
+	Dlg = new DlgRoot(BubDlg, data);
 	switch(type & 0x00f) {
 	case BUBBLE_SQUARE:		Dlg->SetCheck(110, 0L, true);		break;
 	case BUBBLE_UPTRIA:		Dlg->SetCheck(111, 0L, true);		break;
@@ -357,9 +372,12 @@ Bubble::PropertyDlg()
 	if(!Dlg->GetValue(303, &o_pos.fy))	o_pos.fy = fPos.fy;
 	if(!Dlg->GetValue(305, &o_size))	o_size = fs;
 	n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;	n_size = o_size;
-	if(parent->name) sprintf(TmpTxt, "Bubble of %s", parent->name);
-	else strcpy(TmpTxt, "Bubble properties");
-	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 260, Dlg, 0x0L);
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble properties");
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 396, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -413,14 +431,45 @@ Bubble::PropertyDlg()
 		bRet = true;
 		break;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
-	return bRet;
+	CloseDlgWnd(hDlg);		delete Dlg;		return bRet;		free(BubDlg);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Bar properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BarDlg_DlgTmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,1,130,10,55,12\n"
+	"2,3,,,PUSHBUTTON,2,130,25,55,12\n"
+	"3,4,,,PUSHBUTTON,-2,130,40,55,12\n"
+	"4,,5,CHECKED | ISPARENT,GROUP,0,138,40,55,12\n"
+	"5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,120,120\n"
+	"6,7,200,ISPARENT,SHEET,4,5,10,120,120\n"
+	"7,,300,ISPARENT,SHEET,5,5,10,120,120\n"
+	"100,109,,NOSELECT,ODBUTTON,6,18,30,90,50\n"
+	"109,110,,,LTEXT,7,10,80,45,8\n"
+	"110,111,,,RADIO1,8,20,92,25,8\n"
+	"111,112,,,EDTEXT,9,60,92,25,10\n"
+	"112,113,,,LTEXT,-3,87,92,20,8\n"
+	"113,114,,,RADIO1,10,20,104,25,8\n"
+	"114,115,,,EDTEXT,11,60,104,25,10\n"
+	"115,,,,LTEXT,-10,87,104,10,8\n"
+	"200,201,,TOUCHEXIT,RADIO2,12,20,30,45,8\n"
+	"201,205,202,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"202,203,,TOUCHEXIT,RADIO1,13,30,40,35,8\n"
+	"203,204,,TOUCHEXIT,RADIO1,14,30,48,35,8\n"
+	"204,,,TOUCHEXIT,RADIO1,15,30,56,35,8\n"
+	"205,206,,,EDVAL1,16,65,56,35,10\n"
+	"206,207,,TOUCHEXIT,RADIO2,17,20,70,45,8\n"
+	"207,211,208,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"208,209,,TOUCHEXIT,RADIO1,18,30,80,35,8\n"
+	"209,210,,TOUCHEXIT,RADIO1,19,30,88,35,8\n"
+	"210,,,TOUCHEXIT,RADIO1,20,30,96,35,8\n"
+	"211,212,,,EDVAL1,21,65,96,35,10\n"
+	"212,,,,CHECKBOX,22,20,113,50,8\n"
+	"300,301,,,RTEXT,-12,10,50,45,8\n"
+	"301,302,,,EDVAL1,23,60,50,40,10\n"
+	"302,303,,,RTEXT,-13,10,75,45,8\n"
+	"303,,,LASTOBJ,EDVAL1,24,60,75,40,10";
 bool
 Bar::PropertyDlg()
 {
@@ -428,43 +477,17 @@ Bar::PropertyDlg()
 	TabSHEET tab2 = {50, 90, 10, "Baseline"};
 	TabSHEET tab3 = {90, 120, 10, "Edit"};
 	char sTxt1[20], sTxt2[20];
-	DlgInfo BarDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BAR", 130, 10, 55, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 55, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 55, 12},
-		{4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
-		{6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 120},
-		{7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 120},
-		{100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 18, 30, 90, 50},
-		{109, 110, 0, 0x0L, LTEXT, (void*)"bar width:", 10, 80, 45, 8},
-		{110, 111, 0, 0x0L, RADIO1, (void*)" fixed", 20, 92, 25, 8},
-		{111, 112, 0, 0x0L, EDTEXT, &sTxt1[1], 60, 92, 25, 10},
-		{112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 87, 92, 20, 8},
-		{113, 114, 0, 0x0L, RADIO1, (void*)" relative", 20, 104, 25, 8},
-		{114, 115, 0, 0x0L, EDTEXT, &sTxt2[1], 60, 104, 25, 10},
-		{115, 0, 0, 0x0L, LTEXT, (void*)"%", 87, 104, 10, 8},
-		{200, 201, 0, TOUCHEXIT, RADIO2, (void*)"vertical bars", 20, 30, 45, 8},
-		{201, 205, 202, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
-		{202, 203, 0, TOUCHEXIT, RADIO1, (void*)"bottom baseline", 30, 40, 35, 8},
-		{203, 204, 0, TOUCHEXIT, RADIO1, (void*)"top", 30, 48, 35, 8},
-		{204, 0, 0, TOUCHEXIT, RADIO1, (void*)"user y =", 30, 56, 35, 8},
-		{205, 206, 0, 0x0L, EDVAL1, &BarBase.fy, 65, 56, 35, 10},
-		{206, 207, 0, TOUCHEXIT, RADIO2, (void*)"horizontal bars", 20, 70, 45, 8},
-		{207, 211, 208, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
-		{208, 209, 0, TOUCHEXIT, RADIO1, (void*)"left baseline", 30, 80, 35, 8},
-		{209, 210, 0, TOUCHEXIT, RADIO1, (void*)"right", 30, 88, 35, 8},
-		{210, 0, 0, TOUCHEXIT, RADIO1, (void*)"user x =", 30, 96, 35, 8},
-		{211, 212, 0, 0x0L, EDVAL1, &BarBase.fx, 65, 96, 35, 10},
-		{212, 0, 0, 0x0L, CHECKBOX, (void*)"bars centered across baseline", 20, 113, 50, 8},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 50, 45, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 60, 50, 40, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 75, 45, 8},
-		{303, 0, 0, LASTOBJ, EDVAL1, &fPos.fy, 60, 75, 40, 10}};
+	void *dyndata[] = {(void*)"Apply to BAR", (void*)"Apply to PLOT", (void*)&tab1,
+		(void*)&tab2, (void*)&tab3, (void*)OD_filldef, (void*)"bar width:", (void*)" fixed",
+		(void*)&sTxt1[1], (void*)" relative", (void*)&sTxt2[1], (void*)"vertical bars",
+		(void*)"bottom baseline", (void*)"top", (void*)"user y =", (void*)&BarBase.fy,
+		(void*)"horizontal bars", (void*)"left baseline", (void*)"right", (void*)"user x =",
+		(void*)&BarBase.fx, (void*)"bars centered across baseline", (void*)&fPos.fx, (void*)&fPos.fy};
+	DlgInfo *BarDlg = CompileDialog(BarDlg_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	double n_size;
-	int res, tmpType = type;
+	int cb, res, tmpType = type;
 	bool bRet = false;
 	LineDEF newLine, newFillLine;
 	FillDEF newFill;
@@ -477,13 +500,13 @@ Bar::PropertyDlg()
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
 	if(type & BAR_RELWIDTH) {
 		WriteNatFloatToBuff(sTxt2, size);
-		WriteNatFloatToBuff(sTxt1, defs.GetSize(SIZE_BAR));
+		WriteNatFloatToBuff(sTxt1, DefSize(SIZE_BAR));
 		}
 	else {
 		WriteNatFloatToBuff(sTxt1, size);
-		strcpy(sTxt2, " 50");
+		rlp_strcpy(sTxt2, 20, " 50");
 		}
-	Dlg = new DlgRoot(BarDlg);
+	Dlg = new DlgRoot(BarDlg, data);
 	switch (type & 0xff) {
 	case BAR_VERTB:		case BAR_VERTT:		case BAR_VERTU:
 		Dlg->SetCheck(200, 0L, true);
@@ -507,8 +530,11 @@ Bar::PropertyDlg()
 	if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
 	else Dlg->SetCheck(110, 0L, true);
 	if(type & BAR_CENTERED) Dlg->SetCheck(212, 0L, true);
-	if(parent && parent->name) sprintf(TmpTxt, "Bar of %s", parent->name);
-	else strcpy(TmpTxt, "Bar properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar properties");
 	if(!Dlg->GetValue(211, &o_bl.fx))	o_bl.fx = BarBase.fx;
 	if(!Dlg->GetValue(205, &o_bl.fy))	o_bl.fy = BarBase.fy;
 	if(!Dlg->GetValue(301, &o_pos.fx))	o_pos.fx = fPos.fx;
@@ -516,7 +542,7 @@ Bar::PropertyDlg()
 	n_bl.fx = o_bl.fx;			n_bl.fy = o_bl.fy;
 	n_pos.fx = o_pos.fx;		n_pos.fy = o_pos.fy;
 	n_size = size;
-	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 296, Dlg, 0x0L);
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 300, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -606,47 +632,51 @@ Bar::PropertyDlg()
 		bRet = true;
 		break;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(BarDlg);
 	return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Data line properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *LineDlg_DlgTmpl =
+	"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,139,120\n"
+	"5,6,200,ISPARENT,SHEET,2,5,10,139,120\n"
+	"6,,300,ISPARENT | HIDDEN,SHEET,3,5,10,139,120\n"
+	"100,,,NOSELECT,ODBUTTON,9,10,38,130,100\n"
+	"200,201,,,LTEXT,4,10,32,130,100\n"
+	"201,202,,EXRADIO,ODBUTTON,10,12,45,25,25\n"
+	"202,203,,EXRADIO,ODBUTTON,10,37,45,25,25\n"
+	"203,204,,EXRADIO,ODBUTTON,10,62,45,25,25\n"
+	"204,205,,EXRADIO,ODBUTTON,10,87,45,25,25\n"
+	"205,206,,EXRADIO,ODBUTTON,10,112,45,25,25\n"
+	"206,207,,EXRADIO,ODBUTTON,10,37,70,25,25\n"
+	"207,208,,EXRADIO,ODBUTTON,10,62,70,25,25\n"
+	"208,209,,EXRADIO,ODBUTTON,10,87,70,25,25\n"
+	"209,210,,EXRADIO,ODBUTTON,10,112,70,25,25\n"
+	"210,211,,EXRADIO,ODBUTTON,10,37,95,25,25\n"
+	"211,,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
+	"300,301,,,LTEXT,5,15,30,80,9\n"
+	"301,302,,,EDTEXT,7,15,40,119,10\n"
+	"302,303,,,LTEXT,6,15,55,80,9\n"
+	"303,,,LASTOBJ,EDTEXT,8,15,65,119,10";
+
 bool
 DataLine::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 40, 10, "Line"};
 	TabSHEET tab2 = {40, 80, 10, "Style"};
 	TabSHEET tab3 = {80, 120, 10, "Edit"};
-	DlgInfo LineDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
-		{5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
-		{6, 0, 300, ISPARENT | HIDDEN, SHEET, &tab3, 5, 10, 139, 120},
-		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"select style:", 10, 32, 130, 100},
-		{201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 12, 45, 25, 25},
-		{202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 37, 45, 25, 25},
-		{203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 62, 45, 25, 25},
-		{204, 205, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 87, 45, 25, 25},
-		{205, 206, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 112, 45, 25, 25},
-		{206, 207, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 37, 70, 25, 25},
-		{207, 208, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 62, 70, 25, 25},
-		{208, 209, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 87, 70, 25, 25},
-		{209, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 112, 70, 25, 25},
-		{210, 211, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 37, 95, 25, 25},
-		{211, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 62, 95, 25, 25},
-		{300, 301, 0, 0x0L, LTEXT, (void*)"range for x-values", 15, 30, 80, 9},
-		{301, 302, 0, 0x0L, EDTEXT, (void*)ssXref, 15, 40, 119, 10},
-		{302, 303, 0, 0x0L, LTEXT, (void*)"range for y-values", 15, 55, 80, 9},
-		{303, 0, 0, LASTOBJ, EDTEXT, (void*)ssYref, 15, 65, 119, 10}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"select style:", 
+		(void*)"range for x-values", (void*)"range for y-values", (void*)ssXref, (void*)ssYref,
+		(void*)OD_linedef, (void*)(OD_LineStyleTempl)};
+	DlgInfo *LineDlg = CompileDialog(LineDlg_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType = type;
+	int cb, res, tmpType = type;
 	DWORD undo_flags = 0L;
 	LineDEF newLine;
 	bool bRet = false;
@@ -655,11 +685,14 @@ DataLine::PropertyDlg()
 	if(!parent) return false;
 	if(parent->Id == GO_FUNCTION) return parent->PropertyDlg();
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
-	if(!(Dlg = new DlgRoot(LineDlg)))return false;
+	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
 	Dlg->SetCheck(201 + (type & 0x0f), 0L, true);
 	if(ssXref && ssYref) Dlg->ShowItem(6, true);
-	if(parent && parent->name) sprintf(TmpTxt, "Line of %s", parent->name);
-	else strcpy(TmpTxt, "Line properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -678,15 +711,13 @@ DataLine::PropertyDlg()
 	if(res == 1){						//OK pressed
 		Undo.SetDisp(cdisp);
 		if(ssXref && ssYref) {
-			if(Dlg->GetText(301, TmpTxt) && strcmp(ssXref, TmpTxt)) {
-				Undo.String(this, &ssXref, undo_flags);	undo_flags |= UNDO_CONTINUE;
-				if(ssXref = (char*)realloc(ssXref, strlen(TmpTxt)+1))
-					strcpy(ssXref, TmpTxt);
+			if(Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE) && strcmp(ssXref, TmpTxt)) {
+				cb = Undo.String(this, &ssXref, undo_flags);	undo_flags |= UNDO_CONTINUE;
+				if(ssXref = (char*)realloc(ssXref, (cb+=2))) rlp_strcpy(ssXref, cb, TmpTxt);
 				}
-			if(Dlg->GetText(303, TmpTxt) && strcmp(ssYref, TmpTxt)) {
-				Undo.String(this, &ssYref, undo_flags);	undo_flags |= UNDO_CONTINUE;
-				if(ssYref = (char*)realloc(ssYref, strlen(TmpTxt)+1))
-					strcpy(ssYref, TmpTxt);
+			if(Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE) && strcmp(ssYref, TmpTxt)) {
+				cb = Undo.String(this, &ssYref, undo_flags);	undo_flags |= UNDO_CONTINUE;
+				if(ssYref = (char*)realloc(ssYref, (cb+=2))) rlp_strcpy(ssYref, cb, TmpTxt);
 				}
 			if(undo_flags & UNDO_CONTINUE) Command(CMD_UPDATE, 0L, cdisp);
 			parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
@@ -700,8 +731,7 @@ DataLine::PropertyDlg()
 		if(undo_flags & UNDO_CONTINUE) bRet = true;
 		}
 	CloseDlgWnd(hDlg);
-	delete Dlg;
-	return bRet;
+	delete Dlg;		free(LineDlg);		return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -722,15 +752,18 @@ DataPolygon::PropertyDlg()
 	FillDEF newFill;
 	DWORD undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
-	int res;
+	int cb, res;
 	bool bRet = false;
 
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
-	Dlg = new DlgRoot(LineDlg);
-	if(parent && parent->name) sprintf(TmpTxt, "Polygon of %s", parent->name);
-	else strcpy(TmpTxt, "Polygon properties");
-	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 310, 204, Dlg, 0x0L);
+	Dlg = new DlgRoot(LineDlg, data);
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon properties");
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 310, 210, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -809,7 +842,7 @@ RegLine::PropertyDlg()
 		{313, 0, 0, LASTOBJ, LTEXT, (void*)"[data]", 119, 101, 15, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType;
+	int cb, res, tmpType;
 	bool bRet = false;
 	LineDEF newLine;
 	DWORD undo_flags = 0L;
@@ -831,12 +864,20 @@ RegLine::PropertyDlg()
 	case 0x3000:	ty = "sqrt(y)"; break;
 	default:		ty = "y";		break;
 		}
+#ifdef USE_WIN_SECURE
+	sprintf_s(text1, 40, "%s = %.3lf + %.3lf * %s   (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
+	sprintf_s(text2, 40, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
+	sprintf_s(text3, 40, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
+	sprintf_s(text4, 40, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
+	sprintf_s(text5, 40, "%s = a + b * %s", ty, tx);
+#else
 	sprintf(text1, "%s = %.3lf + %.3lf * %s   (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
 	sprintf(text2, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
 	sprintf(text3, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
 	sprintf(text4, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
 	sprintf(text5, "%s = a + b * %s", ty, tx);
-	if(!(Dlg = new DlgRoot(LineDlg))) return false;
+#endif
+	if(!(Dlg = new DlgRoot(LineDlg, data))) return false;
 	Dlg->Activate(211, false);	Dlg->Activate(213, false);
 	switch(type & 0x07) {
 	case 1:		Dlg->SetCheck(202, 0L, true);	break;
@@ -869,10 +910,11 @@ RegLine::PropertyDlg()
 	if(!Dlg->GetValue(310, &o_clip.Ymin)) o_clip.Ymin = uclip.Ymin;
 	if(!Dlg->GetValue(312, &o_clip.Ymax)) o_clip.Ymax = uclip.Ymax;
 	memcpy(&n_clip, &o_clip, sizeof(fRECT));
-	if(parent && parent->name) {
-		sprintf(TmpTxt, "Regression line of %s", parent->name);
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
 		}
-	else strcpy(TmpTxt, "Regression line properties");
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line properties");
 	hDlg = CreateDlgWnd(cp ? TmpTxt : 
 		(char*)"Linear regression analysis step 2/2", 50, 50, 420, 320, Dlg, 0x0L);
 	if(!cp) Dlg->SetCheck(5, 0L, true);
@@ -959,7 +1001,7 @@ SDellipse::PropertyDlg()
 		{259, 0, 0, LASTOBJ, LTEXT, 0L, 82, 108, 30, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType;
+	int cb, res, tmpType;
 	LineDEF newLine;
 	bool bRet = false;
 	DWORD undo_flags = 0L;
@@ -967,16 +1009,19 @@ SDellipse::PropertyDlg()
 
 	if(!parent) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
-	if(!(Dlg = new DlgRoot(ellDlg))) return false;
+	if(!(Dlg = new DlgRoot(ellDlg, data))) return false;
 	if(!(type & 0x10000)) Dlg->SetCheck(200, 0L, true);
 	WriteNatFloatToBuff(TmpTxt, mx);		Dlg->SetText(252, TmpTxt+1);
 	WriteNatFloatToBuff(TmpTxt, my);		Dlg->SetText(254, TmpTxt+1);
-	strcpy(TmpTxt, "+/-");
+	rlp_strcpy(TmpTxt, 4, "+/-");
 	WriteNatFloatToBuff(TmpTxt+3, sd1);		Dlg->SetText(259, TmpTxt);
 	WriteNatFloatToBuff(TmpTxt+3, sd2);		Dlg->SetText(257, TmpTxt);
 	tmpType = type;
-	if(parent && parent->name) sprintf(TmpTxt, "SD ellipse of %s", parent->name);
-	else strcpy(TmpTxt, "SD ellipse properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -1022,7 +1067,7 @@ ErrorBar::PropertyDlg()
 		{104, 105, 0, 0x0L, EDVAL1, &ErrLine.width, 46, 55, 25, 10},
 		{105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 55, 20, 8},
 		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
-		{107, 0, 0, OWNDIALOG, COLBUTTON, (void *)ErrLine.color, 46, 70, 25, 10},
+		{107, 0, 0, OWNDIALOG, COLBUTT, (void *)&ErrLine.color, 46, 70, 25, 10},
 		{200, 0, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 15, 30, 28, 8},
 		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 30, 35, 10},
@@ -1040,7 +1085,7 @@ ErrorBar::PropertyDlg()
 		{505, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 65, 25, 25}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType = type;
+	int cb, res, tmpType = type;
 	double n_sb, o_sb, n_lw, o_lw, n_err, o_err;
 	lfPOINT n_pos, o_pos;
 	DWORD n_col, undo_flags = 0L;
@@ -1050,7 +1095,7 @@ ErrorBar::PropertyDlg()
 
 	if(!parent) return false;
 	desc[0] = 0;
-	if(!(Dlg = new DlgRoot(ErrDlg)))return false;
+	if(!(Dlg = new DlgRoot(ErrDlg, data)))return false;
 	Dlg->SetCheck(500 + (type & 0x7), 0L, true);
 	if(!(Dlg->GetValue(101, &o_sb))) o_sb = SizeBar;
 	if(!(Dlg->GetValue(104, &o_lw))) o_lw = ErrLine.width;
@@ -1058,8 +1103,11 @@ ErrorBar::PropertyDlg()
 	if(!(Dlg->GetValue(301, &o_pos.fx))) o_pos.fx = fPos.fx;
 	if(!(Dlg->GetValue(303, &o_pos.fy))) o_pos.fy = fPos.fy;
 	n_sb = o_sb;	n_lw = o_lw;	n_err = o_err; n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;
-	if(parent && parent->name) sprintf(TmpTxt, "Error bar of %s", parent->name);
-	else strcpy(TmpTxt, "Error properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -1072,7 +1120,7 @@ ErrorBar::PropertyDlg()
 			Dlg->Activate(307, true);	res = -1;	break;
 		case 1:								//accept for this object
 		case 2:								//   or all objects of plot
-			Undo.SetDisp(cdisp);			Dlg->GetText(307, desc);
+			Undo.SetDisp(cdisp);			Dlg->GetText(307, desc, 80);
 			Dlg->GetValue(101, &n_sb);		Dlg->GetValue(104, &n_lw);
 			Dlg->GetColor(107, &n_col);		Dlg->GetValue(305, &n_err);
 			Dlg->GetValue(301, &n_pos.fx);	Dlg->GetValue(303, &n_pos.fy);
@@ -1081,17 +1129,20 @@ ErrorBar::PropertyDlg()
 		}while (res <0);
 	switch (res) {
 	case 1:				//new setting for current error bar only
+		undo_flags = CheckNewFloat(&ferr, o_err, n_err, parent, undo_flags);
+		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
+		if(undo_flags & UNDO_CONTINUE) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
 		if(desc[0] && name && name[0] && strcmp(desc, name)) {
-			Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, strlen(desc)+2);
-			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			cb = Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, (cb+=2));
+			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
 			}
-		else if(desc[0]) {
-			Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, strlen(desc)+2);
-			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+		else if(desc[0] && !name) {
+			cb = Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, (cb+=2));
+			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
 			}
-		else if(name && name[0]) {
+		else if(!desc[0] && name && name[0]) {
 			Undo.String(this, &name, undo_flags);
 			name[0] = 0;			undo_flags |= UNDO_CONTINUE;
 			}
@@ -1099,8 +1150,6 @@ ErrorBar::PropertyDlg()
 		undo_flags = CheckNewFloat(&ErrLine.width, o_lw, n_lw, parent, undo_flags);
 		undo_flags = CheckNewDword(&ErrLine.color, ErrLine.color, n_col, parent, undo_flags);
 		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
-		undo_flags = CheckNewFloat(&ferr, o_err, n_err, parent, undo_flags);
-		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
 		if(undo_flags & UNDO_CONTINUE) bRet = true;
 		break;
 	case 2:				//new settings to all error bars of plot
@@ -1148,7 +1197,7 @@ Arrow::PropertyDlg()
 		{107, 108, 0, 0x0L, EDVAL1, &LineDef.width, 46, 70, 25, 10},
 		{108, 109, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 70, 20, 8},
 		{109, 110, 0, 0x0L, RTEXT, (void*)"color", 15, 82, 28, 8},
-		{110, 0, 0, OWNDIALOG, COLBUTTON, (void *)LineDef.color, 46, 82, 25, 10},
+		{110, 0, 0, OWNDIALOG, COLBUTT, (void *)&LineDef.color, 46, 82, 25, 10},
 		{200, 201, 0, TOUCHEXIT, RADIO1, (void*)"line only", 15, 40, 60, 8},
 		{201, 202, 0, TOUCHEXIT, RADIO1, (void*)"arrow with lines", 15, 55, 60, 8},
 		{202, 0, 0, TOUCHEXIT, RADIO1, (void*)"filled arrow", 15, 70, 60, 8},
@@ -1170,13 +1219,13 @@ Arrow::PropertyDlg()
 	void *hDlg;
 	lfPOINT o_pos1, o_pos2, n_pos1, n_pos2;
 	double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
-	int res, tmptype = type, undo_level = *Undo.pcb;
+	int cb, res, tmptype = type, undo_level = *Undo.pcb;
 	bool bRet = false;
 	DWORD o_col, n_col, undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
 
 	if(!parent) return false;
-	if(!(Dlg = new DlgRoot(ArrowDlg))) return false;
+	if(!(Dlg = new DlgRoot(ArrowDlg, data))) return false;
 	Dlg->GetValue(301, &o_pos2.fx);		Dlg->GetValue(303, &o_pos2.fy);
 	Dlg->GetValue(305, &o_pos1.fx);		Dlg->GetValue(307, &o_pos1.fy);
 	Dlg->GetValue(101, &o_cw);			Dlg->GetValue(104, &o_cl);
@@ -1191,8 +1240,11 @@ Arrow::PropertyDlg()
 		Dlg->ShowItem(2, false);
 		Dlg->ShowItem(308, false);		Dlg->ShowItem(309, false);
 		}
-	if(parent && parent->name) sprintf(TmpTxt, "Arrow of %s", parent->name);
-	else strcpy(TmpTxt, "Arrow properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();			res = Dlg->GetResult();
@@ -1296,7 +1348,7 @@ Box::PropertyDlg()
 		};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType = type;
+	int cb, res, tmpType = type;
 	FillDEF newFill;
 	LineDEF newLine, newHatchLine;
 	DWORD undo_flags = 0L;
@@ -1312,21 +1364,24 @@ Box::PropertyDlg()
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
 	if(type & BAR_RELWIDTH) {
 		WriteNatFloatToBuff(sTxt2, size);
-		WriteNatFloatToBuff(sTxt1, defs.GetSize(SIZE_BAR));
+		WriteNatFloatToBuff(sTxt1, DefSize(SIZE_BAR));
 		}
 	else {
 		WriteNatFloatToBuff(sTxt1, size);
-		strcpy(sTxt2, " 50");
+		rlp_strcpy(sTxt2, 20, " 50");
 		}
-	Dlg = new DlgRoot(BoxDlg);
+	Dlg = new DlgRoot(BoxDlg, data);
 	if(type & BAR_WIDTHDATA) {
 		Dlg->ShowItem(105, false);
 		Dlg->ShowItem(308, true);		Dlg->ShowItem(309, true);
 		}
 	if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
 	else Dlg->SetCheck(110, 0L, true);
-	if(parent && parent->name) sprintf(TmpTxt, "Box of %s", parent->name);
-	else strcpy(TmpTxt, "Box properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box properties");
 	Dlg->GetValue(309, &o_size);
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 290, Dlg, 0x0L);
 	do {
@@ -1453,7 +1508,7 @@ Whisker::PropertyDlg()
 	DlgInfo *ErrDlg = CompileDialog(WhiskerDlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmp_type;
+	int cb, res, tmp_type;
 	DWORD undo_flags = 0L, n_col = LineDef.color;
 	anyOutput *cdisp = Undo.cdisp;
 	lfPOINT n_pos;
@@ -1463,11 +1518,14 @@ Whisker::PropertyDlg()
 
 	if(!parent) return false;
 	desc[0] = 0;	tmp_type = type;
-	Dlg = new DlgRoot(ErrDlg);
+	Dlg = new DlgRoot(ErrDlg, data);
 	Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
 	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lw);
-	if(parent && parent->name) sprintf(TmpTxt, "Whisker of %s", parent->name);
-	else strcpy(TmpTxt, "Whisker properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 339, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -1480,25 +1538,25 @@ Whisker::PropertyDlg()
 		case 2:								//   or all objects of plot
 			Undo.SetDisp(cdisp);			Dlg->GetValue(101, &n_size);
 			Dlg->GetValue(104, &n_lw);		Dlg->GetColor(107, &n_col);
-			Dlg->GetText(309, desc);
+			Dlg->GetText(309, desc, 80);
 			break;
 			}
 		}while (res <0);
 	switch (res) {
 	case 1:				//new setting for current whisker
 		if(desc[0] && name && name[0] && strcmp(desc, name)) {
-			Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, strlen(desc)+2);
-			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			cb = Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, (cb+=2));
+			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
 			}
 		else if(desc[0]) {
-			Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, strlen(desc)+2);
-			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			cb = Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, (cb+=2));
+			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
 			}
 		else if(name && name[0]) {
 			Undo.String(this, &name, undo_flags);
-			name[0] = 0;			undo_flags |= UNDO_CONTINUE;
+			name[0] = 0;					undo_flags |= UNDO_CONTINUE;
 			}
 		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
 		else n_pos.fx = pos1.fx;
@@ -1562,7 +1620,7 @@ DropLine::PropertyDlg()
 		{256, 0, 0, LASTOBJ, CHECKBOX, (void*)"x-axis", 86, 100, 35, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmptype;
+	int cb, res, tmptype;
 	bool bRet = false;
 	LineDEF newLine;
 	DWORD undo_flags = 0L;
@@ -1571,7 +1629,7 @@ DropLine::PropertyDlg()
 
 	if(!parent) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
-	Dlg = new DlgRoot(LineDlg);
+	Dlg = new DlgRoot(LineDlg, data);
 	Dlg->SetCheck(251, 0L, type & DL_LEFT ? true : false);
 	Dlg->SetCheck(252, 0L, type & DL_RIGHT ? true : false);
 	Dlg->SetCheck(253, 0L, type & DL_YAXIS ? true : false);
@@ -1579,8 +1637,11 @@ DropLine::PropertyDlg()
 	Dlg->SetCheck(255, 0L, type & DL_BOTTOM ? true : false);
 	Dlg->SetCheck(256, 0L, type & DL_XAXIS ? true : false);
 	Dlg->GetValue(201, &o_pos.fx);		Dlg->GetValue(203, &o_pos.fy);
-	if(parent->name) sprintf(TmpTxt, "Dropline of %s", parent->name);
-	else strcpy(TmpTxt, "Dropline properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -1656,7 +1717,7 @@ DropLine3D::PropertyDlg()
 		{256, 0, 0, LASTOBJ, CHECKBOX, (void*)"right", 86, 100, 35, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmptype, i;
+	int cb, res, tmptype, i;
 	bool bRet = false;
 	LineDEF newLine;
 	DWORD undo_flags = 0L;
@@ -1665,14 +1726,17 @@ DropLine3D::PropertyDlg()
 
 	if(!parent) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	Dlg = new DlgRoot(LineDlg);
+	Dlg = new DlgRoot(LineDlg, data);
 	for(i = 0; i < 6; i++) {
 		Dlg->SetCheck(251+i, 0L, (type & (1<<i)) ? true : false);
 		}
 	Dlg->GetValue(201, &o_pos.fx);		Dlg->GetValue(203, &o_pos.fy);
 	Dlg->GetValue(205, &o_pos.fz);
-	if(parent->name) sprintf(TmpTxt, "Dropline of %s", parent->name);
-	else strcpy(TmpTxt, "Dropline properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -1742,7 +1806,7 @@ Sphere::PropertyDlg()
 		{104, 105, 0, 0x0L, EDVAL1, &Line.width, 46, 47, 25, 10},
 		{105, 106, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 73, 47, 15, 8},
 		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 59, 28, 8},
-		{107, 108, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 46, 59, 25, 10},
+		{107, 108, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 46, 59, 25, 10},
 		{108, 109, 0, 0x0L, RTEXT, (void*)"fill color", 15, 71, 28, 8},
 		{109, 0, 0, OWNDIALOG, SHADE3D, &newFill, 46, 71, 25, 10},
 		{200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 15, 35, 28, 8},
@@ -1753,7 +1817,7 @@ Sphere::PropertyDlg()
 		{205, 0, 0, LASTOBJ, EDVAL1, &fPos.fz, 46, 59, 35, 10}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res;
+	int cb, res;
 	bool bRet = false, bContinue = false;
 	fPOINT3D n_pos, o_pos;
 	DWORD new_lcolor = Line.color, undo_flags = 0L;
@@ -1762,13 +1826,16 @@ Sphere::PropertyDlg()
 
 	if(!parent) return false;
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
-	Dlg = new DlgRoot(BallDlg);
+	Dlg = new DlgRoot(BallDlg, data);
 	Dlg->GetValue(201, &o_pos.fx);			Dlg->GetValue(203, &o_pos.fy);
 	Dlg->GetValue(205, &o_pos.fz);			Dlg->GetValue(101, &o_size);
 	Dlg->GetValue(104, &o_lsize);
-	if(parent->name) sprintf(TmpTxt, "Ball of %s", parent->name);
-	else strcpy(TmpTxt, "Ball properties");
-	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 216, Dlg, 0x0L);
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball properties");
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 220, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -1854,7 +1921,7 @@ Plane3D::PropertyDlg()
 	DlgInfo *PlaneDlg = CompileDialog(Plane3D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res;
+	int cb, res;
 	bool bRet = false;
 	DWORD new_lcolor = Line.color, undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
@@ -1867,14 +1934,17 @@ Plane3D::PropertyDlg()
 		rb_width = parent->GetSize(SIZE_CELLWIDTH) *100.0;
 		rb_z = parent->GetSize(SIZE_ZPOS);
 		}
-	Dlg = new DlgRoot(PlaneDlg);
+	Dlg = new DlgRoot(PlaneDlg, data);
 	Dlg->GetValue(101, &o_lsize);		Dlg->GetValue(202, &o_rbw);
 	Dlg->GetValue(205, &o_rbz);
 	if(parent && ((parent->Id==GO_RIBBON && parent->type > 1) || parent->Id==GO_GRID3D))
 		Dlg->ShowItem(200, false);								//paravent plot
-	if(parent->Id == GO_RIBBON && parent->type >2) sprintf(TmpTxt, "3D Surface Properties");
-	else if(parent->name) sprintf(TmpTxt, "Plane of %s", parent->name);
-	else strcpy(TmpTxt, "Plane properties");
+	if(parent->Id == GO_RIBBON && parent->type >2) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Surface Properties");
+	else if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -1936,7 +2006,7 @@ Brick::PropertyDlg()
 		{101, 102, 0, 0x0L, EDVAL1, &Line.width, 60, 30, 25, 10},
 		{102, 103, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 30, 20, 8},
 		{103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 18, 42, 40, 8},
-		{104, 105, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 60, 42, 25, 10},
+		{104, 105, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 60, 42, 25, 10},
 		{105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 18, 54, 40, 8},
 		{106, 107, 0, OWNDIALOG, SHADE3D, &newFill, 60, 54, 25, 10},
 		{107, 108, 0, 0x0L, RTEXT, (void*)"column width", 18, 74, 40, 8},
@@ -1955,7 +2025,7 @@ Brick::PropertyDlg()
 		{307, 0, 0, LASTOBJ, EDVAL1, &height, 50, 87, 30, 10}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res;
+	int cb, res;
 	bool bRet = false;
 	DWORD col1 = Line.color, undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
@@ -1965,14 +2035,17 @@ Brick::PropertyDlg()
 
 	if(!parent) return false;
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
-	Dlg = new DlgRoot(ColumnDlg);
+	Dlg = new DlgRoot(ColumnDlg, data);
 	Dlg->GetValue(101, &o_lw);		Dlg->GetValue(301, &o_pos.fx);
 	Dlg->GetValue(303, &o_pos.fy);	Dlg->GetValue(305, &o_pos.fz);
 	Dlg->GetValue(307, &o_height);	Dlg->GetValue(108, &o_width);
 	Dlg->GetValue(111, &o_depth);
 	memcpy(&n_pos, &o_pos, sizeof(fPOINT3D));
-	if(parent->name) sprintf(TmpTxt, "Column of %s", parent->name);
-	else strcpy(TmpTxt, "Column properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 405, 296, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -2082,13 +2155,13 @@ Arrow3D::PropertyDlg()
 	void *hDlg;
 	fPOINT3D o_pos1, o_pos2, n_pos1, n_pos2;
 	double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
-	int res, tmptype = type, undo_level = *Undo.pcb;
+	int cb, res, tmptype = type, undo_level = *Undo.pcb;
 	bool bRet = false;
 	DWORD o_col, n_col, undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
 
 	if(!parent) return false;
-	if(!(Dlg = new DlgRoot(ArrowDlg))) return false;
+	if(!(Dlg = new DlgRoot(ArrowDlg, data))) return false;
 	Dlg->GetValue(301, &o_pos2.fx);		Dlg->GetValue(303, &o_pos2.fy);
 	Dlg->GetValue(305, &o_pos2.fz);		Dlg->GetValue(307, &o_pos1.fx);
 	Dlg->GetValue(309, &o_pos1.fy);		Dlg->GetValue(311, &o_pos1.fz);
@@ -2099,8 +2172,11 @@ Arrow3D::PropertyDlg()
 	case ARROW_TRIANGLE:	Dlg->SetCheck(202, 0L, true);		break;
 	default:				Dlg->SetCheck(200, 0L, true);		break;
 		}
-	if(parent->name) sprintf(TmpTxt, "Arrow of %s", parent->name);
-	else strcpy(TmpTxt, "Arrow properties");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -2176,7 +2252,7 @@ Line3D::PropertyDlg()
 		{100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 30, 130, 90}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res;
+	int cb, res;
 	bool bRet = false;
 	LineDEF newLine;
 	anyOutput *cdisp = Undo.cdisp;
@@ -2184,8 +2260,12 @@ Line3D::PropertyDlg()
 	if(!parent) return false;
 	if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	if(!(Dlg = new DlgRoot(LineDlg)))return false;
-	sprintf(TmpTxt, "Line of %s", parent->name);
+	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 314, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -2238,7 +2318,7 @@ Label::PropertyDlg()
 		{101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 80, 33, 33, 10},
 		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 33, 20, 8},
 		{103, 104, 0, 0x0L, RTEXT, (void*)"color", 30, 45, 45, 8},
-		{104, 107, 0, OWNDIALOG, COLBUTTON, (void *)TextDef.ColTxt, 80, 45, 25, 10},
+		{104, 107, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 80, 45, 25, 10},
 		{105, 106, 0, 0x0L, LTEXT, (void*)"text:", 10, 83, 25, 8},
 		{106, 0, 0, TOUCHEXIT, EDTEXT, (void*)TextDef.text, 10, 95, 149, 10},
 		{107, 108, 0, 0x0L, RTEXT, (void*)"rotation", 30, 57, 45, 8},
@@ -2281,7 +2361,7 @@ Label::PropertyDlg()
 		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 90, 15, 15}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, i, c_style, c_font;
+	int cb, res, i, c_style, c_font;
 	bool RetVal = false, check;
 	double tmp;
 	DWORD undo_flags = 0x0;
@@ -2296,7 +2376,7 @@ Label::PropertyDlg()
 		lspc = 100.0 * parent->GetSize(SIZE_LSPC);
 		}
 	if (lspc < 50.0) lspc = 100.0;
-	if(Dlg = new DlgRoot(LabelDlg)) {
+	if(Dlg = new DlgRoot(LabelDlg, data)) {
 		if(parent->Id == GO_MLABEL) Dlg->ShowItem(150, true);
 		Dlg->TextFont(221, FONT_HELVETICA);		Dlg->TextFont(222, FONT_TIMES);
 		Dlg->TextFont(223, FONT_COURIER);		Dlg->TextFont(224, FONT_GREEK);
@@ -2325,12 +2405,12 @@ Label::PropertyDlg()
 		Dlg->SetText(303, " ");
 		TmpTxt[0] = 0;
 		if(parent->Id == GO_MLABEL) {
-			if(parent->parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
-			else if(parent->parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+			if(parent->parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+			else if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
 			}
 		else {
-			if(parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
-			else if(parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+			if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+			else if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
 			}
 		if(TmpTxt[0]) {
 			Dlg->SetText(302, TmpTxt);			Dlg->Activate(302, false);
@@ -2347,12 +2427,12 @@ Label::PropertyDlg()
 	case LB_Y_PARENT:
 		Dlg->SetText(306, " ");					TmpTxt[0] = 0;
 		if(parent->Id == GO_MLABEL) {
-			if(parent->parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
-			if(parent->parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+			if(parent->parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+			if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
 			}
 		else {
-			if(parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
-			if(parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+			if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+			if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
 			}
 		if(TmpTxt[0]) {
 			Dlg->SetText(305, TmpTxt);			Dlg->Activate(305, false);
@@ -2369,7 +2449,7 @@ Label::PropertyDlg()
 	Dlg->GetValue(302, &o_pos.fx);					Dlg->GetValue(305, &o_pos.fy);
 	Dlg->GetValue(309, &o_dist.fx);					Dlg->GetValue(312, &o_dist.fy);
 	n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;	n_dist.fx = o_dist.fx;	n_dist.fy = o_dist.fy;
-	hDlg = CreateDlgWnd("Label properties", 50, 50, isDataLabel ? 470 : 450, 254, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Label properties", 50, 50, isDataLabel ? 470 : 450, 258, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();			res = Dlg->GetResult();
 		switch (res) {
@@ -2389,7 +2469,7 @@ Label::PropertyDlg()
 			Dlg->GetValue(309, &n_dist.fx);			Dlg->GetValue(312, &n_dist.fy);
 			break;
 		case 106:													//text modified
-			if(!(Dlg->GetText(res, TmpTxt))) TmpTxt[0] = 0;
+			if(!(Dlg->GetText(res, TmpTxt, TMP_TXT_SIZE))) TmpTxt[0] = 0;
 			else {
 				if(!fmt) fmt = new fmtText(0L, 0, 0, TmpTxt);
 				else fmt->SetText(0L, TmpTxt, 0L, 0L);
@@ -2451,10 +2531,12 @@ Label::PropertyDlg()
 			o_dist.fy != n_dist.fy)){
 			pa->Command(CMD_SAVE_TICKS, 0L, 0L);			undo_flags |= UNDO_CONTINUE;
 			}
-		TmpTxt[0] = 0;		Dlg->GetText(106, TmpTxt);
+		TmpTxt[0] = 0;		Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
 		if(res == 1 && TextDef.text && TextDef.text[0] && strcmp(TextDef.text, TmpTxt)) {
-			Undo.String(this, &TextDef.text, undo_flags);	undo_flags |= UNDO_CONTINUE;
-			if(TextDef.text) free(TextDef.text);			TextDef.text = strdup(TmpTxt);
+			Undo.String(this, &TextDef.text, undo_flags);
+			undo_flags |= UNDO_CONTINUE;			cb = (int)strlen(TmpTxt);
+			TextDef.text = (char*)realloc(TextDef.text, (cb+=2));
+			rlp_strcpy(TextDef.text, cb, TmpTxt);
 			}
 		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
 			if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
@@ -2502,6 +2584,103 @@ Label::PropertyDlg()
 	return RetVal;
 }
 
+bool
+TextFrame::PropertyDlg()
+{
+	TabSHEET tab1 = {0, 27, 10, "Text"};
+	TabSHEET tab2 = {27, 57, 10, "Frame"};
+	double lspc2, lspc1 = lspc2 = lspc * 100.0;
+	DlgInfo TextFrmDlg[] = {
+		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+		{3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 119, 100},
+		{5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 119, 100},
+		{50, 0, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+		{100, 101, 0, 0x0L, RTEXT, (void*)"size", 10, 33, 45, 8},
+		{101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 60, 33, 33, 10},
+		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 95, 33, 20, 8},
+		{103, 104, 0, 0x0L, RTEXT, (void*)"color", 10, 45, 45, 8},
+		{104, 150, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 60, 45, 25, 10},
+		{150, 0, 151, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+		{151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 10, 57, 45, 8},
+		{152, 153, 0, 0x0L, INCDECVAL1, &lspc1, 60, 57, 33, 10},
+		{153, 0, 0, 0x0L, LTEXT, (void *)"%", 95, 57, 20, 8},
+		{200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 20, 30, 90, 50},
+		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 45, 15, 15},
+		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 60, 15, 15},
+		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 75, 15, 15},
+		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 90, 15, 15}};
+	DlgRoot *Dlg;
+	void *hDlg;
+	anyOutput *cdisp = Undo.cdisp;
+	int i, res;
+	bool bRet = false;
+	LineDEF newLine, newFillLine;
+	FillDEF newFill;
+	DWORD undo_flags = 0L;
+	TextDEF OldTxtDef, NewTxtDef;
+
+	if(!parent || !data) return false;
+	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+	if(!(Dlg = new DlgRoot(TextFrmDlg, data)))return false;
+	memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF));	OldTxtDef.text = 0L;
+	Dlg->GetValue(101, &OldTxtDef.fSize);			memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
+	Dlg->GetValue(152, &lspc1);
+	hDlg = CreateDlgWnd("Text Frame", 50, 50, 370, 258, Dlg, 0x0L);
+	do{
+		LoopDlgWnd();			res = Dlg->GetResult();
+		switch (res) {
+		case 1:
+			Dlg->GetValue(101, &NewTxtDef.fSize);	Dlg->GetColor(104, &NewTxtDef.ColTxt);
+			Dlg->GetValue(152, &lspc2);			lspc1 /= 100.0;			lspc2 /= 100.0;
+			break;
+		case 600:	case 601:	case 602:	case 603:
+			Undo.SetDisp(cdisp);
+			res = ExecDrawOrderButt(parent, this, res);
+			break;
+			}
+		}while (res < 0);
+	if(res == 1){						//OK pressed
+		Undo.SetDisp(cdisp);
+		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+		memcpy(&newFillLine, &FillLine, sizeof(LineDEF));
+		if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
+			Undo.TextDef(this, &TextDef, undo_flags);
+			memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));	
+			undo_flags |= UNDO_CONTINUE;	TextDef.text = 0L;
+			}
+		undo_flags = CheckNewFloat(&lspc, lspc1, lspc2, parent, undo_flags);
+		if(cmpLineDEF(&Line, &newLine)) {
+			Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
+			memcpy(&Line, &newLine, sizeof(LineDEF));
+			}
+		if(newFill.type && cmpLineDEF(&FillLine, &newFillLine)) {
+			Undo.Line(parent, &FillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
+			memcpy(&FillLine, &newFillLine, sizeof(LineDEF));
+			}
+		if(cmpFillDEF(&Fill, &newFill)) {
+			Undo.Fill(parent, &Fill, undo_flags);		undo_flags |= UNDO_CONTINUE;
+			memcpy(&Fill, &newFill, sizeof(FillDEF));
+			}
+		Fill.hatch = &FillLine;
+		if(undo_flags & UNDO_CONTINUE){
+			bRet = bModified = true;					lines2text();
+			Undo.TextBuffer(this, &csize, &cpos, &text, undo_flags, cdisp);
+			if(lines) {
+				for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+				free(lines);			lines = 0L;
+				}
+			HideTextCursor();			cur_pos.x = cur_pos.y = 0;
+			}
+		}
+	CloseDlgWnd(hDlg);		delete Dlg;
+	return bRet;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // segment properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2556,7 +2735,7 @@ segment::PropertyDlg()
 	if(!parent) return false;
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&segLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&segFill, 0);
-	Dlg = new DlgRoot(SegDlg);
+	Dlg = new DlgRoot(SegDlg, data);
 	Dlg->GetValue(216, &old_r1);		new_r1 = old_r1;
 	Dlg->GetValue(213, &old_r2);		new_r2 = old_r2;
 	Dlg->GetValue(201, &old_cent.fx);	new_cent.fx = old_cent.fx;
@@ -2662,7 +2841,7 @@ polyline::PropertyDlg()
 
 	if(!parent) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
-	if(!(Dlg = new DlgRoot(LineDlg)))return false;
+	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
 	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
 	hDlg = CreateDlgWnd("line properties", 50, 50, 410, 314, Dlg, 0x0L);
 	do{
@@ -2727,7 +2906,7 @@ polygon::PropertyDlg()
 
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
-	Dlg = new DlgRoot(PolygDlg);
+	Dlg = new DlgRoot(PolygDlg, data);
 	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
 	hDlg = CreateDlgWnd("polygon properties", 50, 50, 310, 224, Dlg, 0x0L);
 	do{
@@ -2826,7 +3005,7 @@ rectangle::PropertyDlg()
 
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
-	if(!(Dlg = new DlgRoot(RecDlg)))return false;
+	if(!(Dlg = new DlgRoot(RecDlg, data)))return false;
 	Dlg->GetValue(201, &old_fp1.fx);		Dlg->GetValue(204, &old_fp1.fy);
 	Dlg->GetValue(207, &old_fp2.fx);		Dlg->GetValue(210, &old_fp2.fy);
 	if(type != 2) Dlg->ShowItem(101, false);
@@ -2937,8 +3116,7 @@ PlotScatt::CreateBarChart()
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
 	UseRangeMark(data, 1, TmpTxt);
-	if(!(Dlg = new DlgRoot(BarDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(BarDlg, data)))return false;
 	hDlg = CreateDlgWnd("Simple Bar Chart", 50, 50, 370, 280, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -2949,8 +3127,13 @@ PlotScatt::CreateBarChart()
 			break;
 		case 1:
 			if(rY) delete rY;
-			if(Dlg->GetText(101, TmpTxt)) rY = new AccRange(TmpTxt);
-			yRange = strdup(TmpTxt);
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)){
+				rY = new AccRange(TmpTxt);
+				yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+				}
+			else {
+				rY = 0L;		yRange = 0L;
+				}
 			if(!(n = rY ? rY->CountItems() : 0)) {
 				res = -1;
 				ErrorBox("Data range not valid.");
@@ -3054,7 +3237,7 @@ PlotScatt::PropertyDlg()
 	double x, y, e;
 	lfPOINT fp1, fp2;
 	bool bRet = false, bLayout = false, bContinue = false;
-	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
 		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
 	AccRange *rX, *rY, *rE, *rL;
 
@@ -3062,9 +3245,7 @@ PlotScatt::PropertyDlg()
 	if(Id == GO_BARCHART) return CreateBarChart();
 	UseRangeMark(data, 1, text1, text2, text3, text4);
 	rX = rY = rE = rL = 0L;
-	if(!(Dlg = new DlgRoot(XYDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);			Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(304, CMD_SET_DATAOBJ, data);			Dlg->ItemCmd(402, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(XYDlg, data)))return false;
 #ifdef _WINDOWS
 	for(i = 104; i <= 107; i++) Dlg->TextSize(i, 12);
 #else
@@ -3101,7 +3282,7 @@ PlotScatt::PropertyDlg()
 		case 1:								// OK
 			if(rX) delete rX;	if(rY) delete rY; if(rE) delete rE;
 			rX = rY = rE = 0L;						// check x-range
-			if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
 			if(!(n = rX ? rX->CountItems() : 0)) {
 				Dlg->SetCheck(4, 0L, true);
 				res = -1;
@@ -3109,7 +3290,7 @@ PlotScatt::PropertyDlg()
 				ErrorBox("X-range not specified\nor not valid.");
 				}
 			else {							// check y-range
-				if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
+				if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
 				if(n != (rY ? rY->CountItems() : 0)) {
 					Dlg->SetCheck(4, 0L, true);
 					res = -1;
@@ -3120,7 +3301,7 @@ PlotScatt::PropertyDlg()
 				}
 			//check for error bar
 			if(res >0 && Dlg->GetCheck(301)) {
-				if(Dlg->GetText(304, TmpTxt)) rE = new AccRange(TmpTxt);
+				if(Dlg->GetText(304, TmpTxt, TMP_TXT_SIZE)) rE = new AccRange(TmpTxt);
 				if(n != (rE ? rE->CountItems() : 0)) {
 					Dlg->SetCheck(6, 0L, true);
 					res = -1;
@@ -3133,7 +3314,7 @@ PlotScatt::PropertyDlg()
 				}
 			//check for data labels
 			if(res >0 && Dlg->GetCheck(400)) {
-				if(Dlg->GetText(402, TmpTxt)) rL = new AccRange(TmpTxt);
+				if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) rL = new AccRange(TmpTxt);
 				if(n != (rL ? rL->CountItems() : 0)) {
 					Dlg->SetCheck(7, 0L, true);
 					res = -1;
@@ -3164,8 +3345,8 @@ PlotScatt::PropertyDlg()
 	if(res == 1 && n && rX && rY){				//OK pressed
 		Command(CMD_FLUSH, 0L, 0L);
 		nPoints = n;
-		if(Dlg->GetText(101, TmpTxt)) xRange = strdup(TmpTxt);
-		if(Dlg->GetText(103, TmpTxt)) yRange = strdup(TmpTxt);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		//Create graphic objects
 		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
@@ -3180,12 +3361,17 @@ PlotScatt::PropertyDlg()
 		if(Dlg->GetCheck(203)) Arrows = (Arrow**)calloc(nPoints, sizeof(Arrow*));
 		if(Dlg->GetCheck(301) && rE) {					//error bars ?
 			Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
-			if(Dlg->GetText(304, TmpTxt)) ErrRange = strdup(TmpTxt);
-			rE->GetFirst(&m, &n);	rE->GetNext(&m, &n);
+			if(Dlg->GetText(304, TmpTxt, TMP_TXT_SIZE)){
+				ErrRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+				rE->GetFirst(&m, &n);	rE->GetNext(&m, &n);
+				}
+			else {
+				rE = 0L;		ErrRange = 0L;
+				}
 			}
 		if(Dlg->GetCheck(400) && rL) {					//labels ?
 			Labels = (Label**)calloc(nPoints, sizeof(Label*));
-			if(Dlg->GetText(402, TmpTxt)) LbRange = strdup(TmpTxt);
+			if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) LbRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 			rL->GetFirst(&o, &p);	rL->GetNext(&o, &p);
 			}
 		if(Dlg->GetCheck(250) && nPoints >1) TheLine = new DataLine(this, data, xRange, yRange); 
@@ -3282,18 +3468,16 @@ xyStat::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
-	int i, res, width, height;
+	int i, res, width, height, cb_mdesc;
 	double x, y, e, f, dx, dy;
 	lfPOINT fp1, fp2;
-	char errdesc[40];
-	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+	char errdesc[40], *mdesc;
+	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
 		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
 
 	if(!parent || !data) return false;
 	UseRangeMark(data, 1, text1, text2);
-	if(!(Dlg = new DlgRoot(StatDlg)))return false;
-	Dlg->ItemCmd(102, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(104, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(StatDlg, data)))return false;
 	text1[0] = text2[0] = 0;
 	hDlg = CreateDlgWnd("Mean and Error Plot", 50, 50, 370, 450, Dlg, 0x0L);
 	do {
@@ -3304,12 +3488,13 @@ xyStat::PropertyDlg()
 			if(Dlg->GetCheck(10)) res=-1;
 			break;
 		case 1:
-			if(!(Dlg->GetText(102, text1) && Dlg->GetText(104, text2) && text1[0] && text2[0])) res = 2;
+			if(!(Dlg->GetText(102, text1, 100) && Dlg->GetText(104, text2, 100) && text1[0] && text2[0])) res = 2;
 			break;
 			}
 		}while (res <0);
 	if(res == 1) {
-		xRange = strdup(text1);		yRange = strdup(text2);
+		xRange = (char*)memdup(text1, ((int)strlen(text1))+2, 0);
+		yRange = (char*)memdup(text2, ((int)strlen(text2))+2, 0);
 		type = 0;
 		if(Dlg->GetCheck(201)) type |= 0x0001;		if(Dlg->GetCheck(202)) type |= 0x0002;
 		if(Dlg->GetCheck(203)) type |= 0x0004;
@@ -3320,41 +3505,65 @@ xyStat::PropertyDlg()
 		if(Dlg->GetCheck(305)) type |= 0x1000;
 		if(Dlg->GetCheck(401)) type |= 0x2000;		if(Dlg->GetCheck(402)) type |= 0x4000;
 		Dlg->GetValue(306, &ci);					TmpTxt[0] = 0;
-		if(Dlg->GetText(404, TmpTxt) && TmpTxt[0]) case_prefix = strdup(TmpTxt);
+		if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		CreateData();
 		if(type && curr_data) {
+			switch (type & 0x00f0) {
+				case 0x0010:		mdesc = "Mean";					break;
+				case 0x0020:		mdesc = "Geometric mean";		break;
+				case 0x0040:		mdesc = "Harmonic mean";		break;
+				case 0x0080:		mdesc = "Median";				break;
+				default:			mdesc = "n.a.";					break;
+				}
+			cb_mdesc = (int)strlen(mdesc);
 			curr_data->GetSize(&width, &height);		nPoints = height;
+#ifdef USE_WIN_SECURE
+			sprintf_s(text1, 100, "a1:a%d", height);	sprintf_s(text2, 100, "b1:b%d", height);
+#else
 			sprintf(text1, "a1:a%d", height);			sprintf(text2, "b1:b%d", height);
+#endif
 			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 			for(i= 0; i < height; i++) {
 				if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y))
 					CheckBounds(x, y);
 				}
 			if(type & 0x0001) {
-				if(nPoints >1) TheLine = new DataLine(this, curr_data, text1, text2); 
+				if(nPoints >1 && (TheLine = new DataLine(this, curr_data, text1, text2)) &&
+					(TheLine->name = (char*)malloc(cb_mdesc+2))) rlp_strcpy(TheLine->name, cb_mdesc+2, mdesc);
+
 				}
 			if((type & 0x0002) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
 				for(i = 0; i < height; i++) {
 					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
-						&& (Symbols[i] = new Symbol(this, curr_data, x, y, DefSym, 0, i, 1, i)))
+						&& (Symbols[i] = new Symbol(this, curr_data, x, y, DefSym, 0, i, 1, i))){
 						Symbols[i]->idx = i;
+						if(Symbols[i]->name = (char*)malloc(cb_mdesc+2))
+							rlp_strcpy(Symbols[i]->name, cb_mdesc+2, mdesc);
+						}
 					}
 				}
 			if((type & 0x0004) && (Bars = (Bar**)calloc(nPoints, sizeof(Bar*)))) {
 				for(i = 0; i < height; i++) {
-					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y))
-						Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i);
+					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
+						&& (Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i))){
+						if(Bars[i]->name = (char*)malloc(cb_mdesc+2))
+							rlp_strcpy(Bars[i]->name, cb_mdesc+2, mdesc);
+						}
 					}
 				}
 			if(type & 0x1f00) {
 				Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
 				switch(type & 0x1f00) {
-				case 0x0100:	strcpy(errdesc, "Std. Dev.");			break;
-				case 0x0200:	strcpy(errdesc, "Std. Err.");			break;
-				case 0x0400:	strcpy(errdesc, "25, 75% Perc.");		break;
-				case 0x0800:	strcpy(errdesc, "Min./Max.");			break;
-				case 0x1000:	sprintf(errdesc, "'%g%% CI", ci);		break;
-				default:		strcpy(errdesc, "error");
+				case 0x0100:	rlp_strcpy(errdesc, 40, "Std. Dev.");			break;
+				case 0x0200:	rlp_strcpy(errdesc, 40, "Std. Err.");			break;
+				case 0x0400:	rlp_strcpy(errdesc, 40, "25, 75% Perc.");		break;
+				case 0x0800:	rlp_strcpy(errdesc, 40, "Min./Max.");			break;
+#ifdef USE_WIN_SECURE
+				case 0x1000:	sprintf_s(errdesc, 40, "'%g%% CI", ci);			break;
+#else
+				case 0x1000:	sprintf(errdesc, "'%g%% CI", ci);				break;
+#endif
+				default:		rlp_strcpy(errdesc, 40, "error");
 					}
 				}
 			if((type & 0x1300) && Errors) {
@@ -3376,7 +3585,7 @@ xyStat::PropertyDlg()
 					}
 				}
 			if((type & 0x6000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
-				dy = -0.4 * defs.GetSize(SIZE_SYMBOL);
+				dy = -0.4 * DefSize(SIZE_SYMBOL);
 				if(type & 0x2000){
 					lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
 					dx = 0.0;
@@ -3411,48 +3620,63 @@ xyStat::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Frequency distribution
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *FreqDlg_Tmpl =
+	"1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,153\n"
+	"5,10,200,ISPARENT,SHEET,2,5,10,120,153\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,101,,,LTEXT,3,10,25,60,8\n"
+	"101,102,,,RANGEINPUT,-15,10,38,110,10\n"
+	"102,103,120,ISPARENT | CHECKED,GROUPBOX,4,10,55,110,42\n"
+	"103,,150,ISPARENT | CHECKED,GROUPBOX,5,10,102,110,57\n" 
+	"120,121,,CHECKED,RADIO1,6,15,60,30,9\n"
+	"121,122,,, EDVAL1,7,47,60,15,10\n"
+	"122,123,,, LTEXT,8,64,60,35,8\n"
+	"123,124,,, RADIO1,9, 15, 72, 45, 9\n"
+	"124,125,,, EDTEXT,-16,65,72,50,10\n"
+	"125,126,,, RTEXT,10,15,84, 47,8\n"
+	"126,,,,EDTEXT,-16,65,84,50,10\n"
+	"150,151,,ISRADIO,CHECKBOX,13,15,107,30, 8\n"
+	"151,152,,ISRADIO,CHECKBOX,14,15,117,30, 8\n"
+	"152,153,,ISRADIO,CHECKBOX,15,65,107,30, 8\n"
+	"153,154,,ISRADIO,CHECKBOX,16,65,117,30,8\n"
+	"154,155,,ISRADIO,CHECKBOX,17,15,127,30,8\n"
+	"155,156,,ISRADIO,CHECKBOX,18,15,137,30,8\n"
+	"156,,,ISRADIO,CHECKBOX,19,15,147,30,8\n"
+	"200,, 210,ISPARENT | CHECKED,GROUPBOX,11,10,27,110,61\n" 
+	"210,,,LASTOBJ | NOSELECT,ODBUTTON,12,25,34,90,50";
+
 bool
 FreqDist::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 25, 10, "Data"};
 	TabSHEET tab2 = {25, 52, 10, "Style"};
-	DlgInfo FreqDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 113},
-		{5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 113},
-		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
-		{101, 102, 0, 0x0L, RANGEINPUT, TmpTxt, 10, 38, 110, 10},
-		{102, 103, 120, ISPARENT | CHECKED, GROUPBOX, (void*)" classes ", 10, 55, 110, 42},
-		{103, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" plot distribution ", 10, 102, 110, 17}, 
-		{120, 121, 0, CHECKED, RADIO1, (void*)"create", 15, 60, 30, 9},
-		{121, 122, 0, 0x0L, EDTEXT, (void*)"7", 47, 60, 15, 10},
-		{122, 123, 0, 0x0L, LTEXT, (void*)"classes and bars", 64, 60, 35, 8},
-		{123, 124, 0, 0x0L, RADIO1, (void*)"class size is", 15, 72, 45, 9},
-		{124, 125, 0, 0x0L, EDTEXT, 0L, 65, 72, 50, 10},
-		{125, 126, 0, 0x0L, RTEXT, (void*)"starting at", 15, 84, 47, 8},
-		{126, 0, 0, 0x0L, EDTEXT, 0L, 65, 84, 50, 10},
-		{150, 151, 0, ISRADIO, CHECKBOX, (void*)" normal", 15, 107, 30, 8},
-		{151, 0, 0, ISRADIO, CHECKBOX, (void*)" log-normal", 65, 107, 30, 8},
-		{200, 0, 210, ISPARENT | CHECKED, GROUPBOX, (void*)" bar style ", 10, 27, 110, 61}, 
-		{210, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 34, 90, 50},
-		{800, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"spread sheet range for values",
+		(void*)" classes ", (void*)" plot distribution ", (void*)"create", (void*)&step,
+		(void*)"classes and bars", (void*)"class size is", (void*)"starting at",
+		(void*)" bar style ", (void*)OD_filldef, (void*)" normal", (void*)" log-normal",
+		(void*)" binomial", (void*)" poisson", (void*)" exponential", (void*)" rectangular",
+		(void*)" chi-square"};
+	DlgInfo *FreqDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
-	int res;
+	int res, r, c;
+	double tmp;
 	char *mrk;
+	AccRange *aR;
 
 	if(!parent || !data) return false;
+	if(!(FreqDlg = CompileDialog(FreqDlg_Tmpl, dyndata))) return false;
+	step = 7;	TmpTxt[100] = 0;
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
-	if(data->Command(CMD_GETMARK, &mrk, 0L)) strcpy(TmpTxt, mrk);
+	if(data->Command(CMD_GETMARK, &mrk, 0L)) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
 	else TmpTxt[0] = 0;
-	if(!(Dlg = new DlgRoot(FreqDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
-	hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 280, Dlg, 0x0L);
+	if(!(Dlg = new DlgRoot(FreqDlg, data)))return false;
+	hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 370, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -3461,17 +3685,19 @@ FreqDist::PropertyDlg()
 			if(Dlg->GetCheck(10)) res=-1;
 			break;
 		case 1:
-			if(Dlg->GetText(101, TmpTxt) && TmpTxt[0]) {
-				if(ssRef) free(ssRef);
-				ssRef = strdup(TmpTxt);
-				}
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssRef = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 			if(Dlg->GetCheck(150)) type = 1;
 			else if(Dlg->GetCheck(151)) type = 2;
+			else if(Dlg->GetCheck(154)) type = 3;
+			else if(Dlg->GetCheck(155)) type = 4;
+			else if(Dlg->GetCheck(156)) type = 5;
+			else if(Dlg->GetCheck(152)) type = 10;
+			else if(Dlg->GetCheck(153)) type = 11;
 			else type = 0;
 			break;
 			}
 		}while (res <0);
-	if(res==1 && (plots = (GraphObj**)calloc(nPlots=2, sizeof(GraphObj*)))) {
+	if(res==1 && (plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*)))) {
 		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
 		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
 		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
@@ -3480,10 +3706,18 @@ FreqDist::PropertyDlg()
 		else {
 			Dlg->GetValue(121, &step);		ProcData(-1);
 			}
+		if(y_info = (char*)malloc(25*sizeof(char))) rlp_strcpy(y_info, 25, "No. of observations");
+		if(x_info = (char*)malloc(25*sizeof(char))){
+			rlp_strcpy(x_info, 25, "Categories");
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && (aR = new AccRange(TmpTxt))) {
+				if(aR->GetFirst(&c, &r) && !data->GetValue(r, c, &tmp) && data->GetText(r, c, TmpTxt, 150, false))
+					rlp_strcpy(x_info, 25, TmpTxt);
+				delete aR;
+				}
+			}
 		if(plots[0]) bRet = true;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(FreqDlg);
 	return bRet;
 }
 
@@ -3530,8 +3764,7 @@ Regression::PropertyDlg()
 	if(!parent || !data) return false;
 	rX = rY = 0L;
 	UseRangeMark(data, 1, text1, text2);
-	if(!(Dlg = new DlgRoot(RegDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(RegDlg, data)))return false;
 	hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 225, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -3547,7 +3780,7 @@ Regression::PropertyDlg()
 		case 1:								// OK
 			if(rX) delete rX;	if(rY) delete rY;
 			rX = rY = 0L;						// check x-range
-			if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
 			if(!(n = rX ? rX->CountItems() : 0)) {
 				Dlg->SetCheck(4, 0L, true);
 				res = -1;
@@ -3555,7 +3788,7 @@ Regression::PropertyDlg()
 				ErrorBox("X-range not specified\nor not valid.");
 				}
 			else {							// check y-range
-				if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
+				if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
 				if(n != (rY ? rY->CountItems() : 0)) {
 					res = -1;
 					bContinue = true;
@@ -3567,8 +3800,8 @@ Regression::PropertyDlg()
 		}while (res <0);
 	if(res==1 && n && rX && rY && (values =(lfPOINT*)calloc(nPoints=n, sizeof(lfPOINT)))){				//OK pressed
 		Command(CMD_FLUSH, 0L, 0L);
-		if(Dlg->GetText(101, TmpTxt)) xRange = strdup(TmpTxt);
-		if(Dlg->GetText(103, TmpTxt)) yRange = strdup(TmpTxt);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
 		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
@@ -3665,13 +3898,13 @@ BubblePlot::PropertyDlg()
 		{204, 205, 0, 0x0L, SYMRADIO, (void *)&syms[3], 90, 40, 20, 20},
 		{205, 206, 0, 0x0L, LTEXT, (void*)"outline:", 7, 67, 45, 8},
 		{206, 207, 0, 0x0L, RTEXT, (void*)"color", 7, 75, 20, 8},
-		{207, 208, 0, OWNDIALOG, COLBUTTON, (void *)BubbleLine.color, 29, 75, 25, 10},
+		{207, 208, 0, OWNDIALOG, COLBUTT, (void *)&BubbleLine.color, 29, 75, 25, 10},
 		{208, 209, 0, 0x0L, RTEXT, (void*)"line width", 67, 75, 20, 8},
 		{209, 210, 0, 0x0L, EDVAL1, &BubbleLine.width, 88, 75, 25, 10},
 		{210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 114, 75, 15, 8},
 		{211, 212, 0, 0x0L, LTEXT, (void*)"fill:", 7, 97, 45, 8},
 		{212, 213, 0, 0x0L, RTEXT, (void*)"color", 7, 105, 20, 8},
-		{213, 214, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)BubbleFill.color, 29, 105, 25, 10},
+		{213, 214, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&BubbleFill.color, 29, 105, 25, 10},
 		{214, 215, 0, 0x0L, RTEXT, (void*)"pattern", 67, 105, 20, 8},
 		{215, 0, 0, TOUCHEXIT | OWNDIALOG, FILLBUTTON, (void *)&ShowFill, 88, 105, 25, 10},
 		{300, 301, 0, 0x0L, LTEXT, (void*)"Sizes are given as", 10, 30, 110, 8},
@@ -3698,10 +3931,7 @@ BubblePlot::PropertyDlg()
 	memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
 	if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
 	ShowFill.hatch = &ShowFillLine;
-	if(!(Dlg = new DlgRoot(PlotDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(105, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
 	hDlg = CreateDlgWnd("Create Bubble Plot", 50, 50, 400, 300, Dlg, 0x0L);
 	rX = rY = rS = 0L;
 	do {
@@ -3726,8 +3956,8 @@ BubblePlot::PropertyDlg()
 			res = -1;
 			break;
 		case 1:						//OK button
-			if(Dlg->GetText(101, text1) && Dlg->GetText(103, text2) && 
-				Dlg->GetText(105, text3) && (rX = new AccRange(text1)) &&
+			if(Dlg->GetText(101, text1, 100) && Dlg->GetText(103, text2, 100) && 
+				Dlg->GetText(105, text3, 100) && (rX = new AccRange(text1)) &&
 				(rY = new AccRange(text2)) && (rS = new AccRange(text3))) {
 				if((i = rX->CountItems()) == rY->CountItems() && i == rS->CountItems()){
 					// OK pressed and ranges checked: exit loop and process data
@@ -3778,27 +4008,32 @@ BubblePlot::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Polar plot properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddPolDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,140,14,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,140,29,45,12\n"
+	"3,10,200,ISPARENT | CHECKED,GROUPBOX,1,5,14,131,96\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"200,201,,CHECKED | EXRADIO,ODBUTTON,2,10,24,20,20\n"
+	"201,202,,EXRADIO,ODBUTTON,2,30,24,20,20\n"
+	"202,203,,EXRADIO,ODBUTTON,2,50,24,20,20\n"
+	"203,204,,EXRADIO,ODBUTTON,2,70,24,20,20\n"
+	"204,210,,EXRADIO,ODBUTTON,2,90,24,20,20\n"
+	"210,211,,,LTEXT,3,10,50,50,8\n"
+	"211,212,,,RANGEINPUT,-15,20,62,100,10\n"
+	"212,213,,,LTEXT,4,10,75,50,8\n"
+	"213,,,LASTOBJ,RANGEINPUT,-16,20,87,100,10";
+
 bool
 PolarPlot::AddPlot()
 {
-	char text1[100], text2[100];
-	DlgInfo PolDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
-		{3, 0, 200, ISPARENT | CHECKED, GROUPBOX, (void*)" select template and data range ", 5, 10, 131, 100},
-		{200, 201, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 10, 20, 20, 20},
-		{201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 30, 20, 20, 20},
-		{202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 50, 20, 20, 20},
-		{203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 70, 20, 20, 20},
-		{204, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 90, 20, 20, 20},
-		{210, 211, 0, 0x0L, LTEXT, (void*)"range for x-data (circular or angular data)", 10, 50, 50, 8},
-		{211, 212, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 62, 100, 10},
-		{212, 213, 0, 0x0L, LTEXT, (void*)"range for y-data (radial data)", 10, 75, 50, 8},
-		{213, 0, 0, LASTOBJ, RANGEINPUT, (void*)text2, 20, 87, 100, 10}};
+	void *dyndata[] = {(void*)" select template and data range ", (void*)OD_PolarTempl,
+		(void*)"range for x-data (circular or angular data)",
+		(void*)"range for y-data (radial data)"};
+	DlgInfo *PolDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, j, k, l, ic, n, res, cType = 200;
-	bool bRet = false;
+	bool bRet = false, bContinue = false;
 	double x, y;
 	AccRange *rX = 0L, *rY = 0L;
 	Symbol **Symbols = 0L;
@@ -3808,14 +4043,21 @@ PolarPlot::AddPlot()
 	anyOutput *cdisp = Undo.cdisp;
 
 	if(!parent || !data) return false;
-	UseRangeMark(data, 1, text1, text2);
-	if(!(Dlg = new DlgRoot(PolDlg)))return false;
-	Dlg->ItemCmd(211, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(213, CMD_SET_DATAOBJ, data);
+	if(!(PolDlg = CompileDialog(AddPolDlg_Tmpl, dyndata))) return false;
+	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+	if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
 	hDlg = CreateDlgWnd("Add Polar Plot", 50, 50, 388, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch (res) {
+		case 0:								// focus lost
+			if(bContinue) res = -1;
+			else if(Dlg->GetCheck(10)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
 		case 200: case 201:	case 202:	case 203:	case 204:
 			if(res == 204) {
 				Dlg->Activate(211, false);			Dlg->Activate(213, false);
@@ -3831,8 +4073,8 @@ PolarPlot::AddPlot()
 			break;
 			}
 		}while (res <0);
-	if(res == 1 && Dlg->GetText(211, text1) && Dlg->GetText(213, text2) && 
-		(rX = new AccRange(text1)) && (rY = new AccRange(text2)) &&
+	if(res == 1 && Dlg->GetText(211, TmpTxt, 100) && Dlg->GetText(213, TmpTxt+100, 100) && 
+		(rX = new AccRange(TmpTxt)) && (rY = new AccRange(TmpTxt+100)) &&
 		(n = rX ? rX->CountItems() : 0) && 
 		(tmpPlots = (Plot**)realloc(Plots, (nPlots+2)*sizeof(Plot*)))) {
 		Undo.SetDisp(cdisp);
@@ -3840,11 +4082,11 @@ PolarPlot::AddPlot()
 		if(Dlg->GetCheck(200) || Dlg->GetCheck(201)) 
 			Symbols = (Symbol**) calloc(n+1, sizeof(Symbol*));
 		if(Dlg->GetCheck(201) || Dlg->GetCheck(202)) 
-			TheLine = new DataLine(this, data, text1, text2);
+			TheLine = new DataLine(this, data, TmpTxt, TmpTxt+100);
 		else if(Dlg->GetCheck(203))
-			TheLine = new DataPolygon(this, data, text1, text2);
+			TheLine = new DataPolygon(this, data, TmpTxt, TmpTxt+100);
 		else if(Dlg->GetCheck(204)) {
-			if(func = new Function(this, data)){
+			if(func = new Function(this, data, "Function")){
 				if(bRet = func->PropertyDlg()){
 					Undo.SetGO(this, (GraphObj**) &Plots[nPlots++], func, 0L);
 					memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
@@ -3868,7 +4110,7 @@ PolarPlot::AddPlot()
 			}
 		}
 	CloseDlgWnd(hDlg);
-	delete Dlg;
+	delete Dlg;			free(PolDlg);
 	if(rX) delete rX;	if(rY) delete rY;
 	return bRet;
 }
@@ -3896,7 +4138,7 @@ PolarPlot::Config()
 		}
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&OutLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
-	Dlg = new DlgRoot(PPDlg);
+	Dlg = new DlgRoot(PPDlg, data);
 	if(!(type & 0x01))Dlg->SetCheck(101, 0L, true);
 	hDlg = CreateDlgWnd("Polar Plot properties", 50, 50, 310, 234, Dlg, 0x0L);
 	do{
@@ -3980,14 +4222,13 @@ PolarPlot::PropertyDlg()
 	tlbdef.ColTxt = defs.Color(COL_AXIS);
 	tlbdef.ColBg = 0x00ffffffL;
 	tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
-	tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
+	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
 	tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
 	tlbdef.Style = TXS_NORMAL;
 	tlbdef.Mode = TXM_TRANSPARENT;
 	tlbdef.Font = FONT_HELVETICA;
 	tlbdef.text = 0L;
-	if(!(Dlg = new DlgRoot(PolDlg)))return false;
-	Dlg->ItemCmd(211, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(213, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
 	hDlg = CreateDlgWnd("Create Polar Plot", 50, 50, 388, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -4046,7 +4287,7 @@ PolarPlot::PropertyDlg()
 			parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT);
 		rad_axis.loc[0].fy = rad_axis.Center.fy - rad_axis.Radius;
 		rad_axis.loc[1].fy = rad_axis.Center.fy;
-		if(Dlg->GetText(211, text1) && Dlg->GetText(213, text2) && 
+		if(Dlg->GetText(211, text1, 100) && Dlg->GetText(213, text2, 100) && 
 			(rX = new AccRange(text1)) && (rY = new AccRange(text2)) &&
 			(n = rX ? rX->CountItems() : 0) && (Plots = (Plot**)calloc(2, sizeof(Plot*)))) {
 			if(Dlg->GetCheck(200) || Dlg->GetCheck(201)) 
@@ -4056,7 +4297,7 @@ PolarPlot::PropertyDlg()
 			else if(Dlg->GetCheck(203))
 				TheLine = new DataPolygon(this, data, text1, text2);
 			else if(Dlg->GetCheck(204)) {
-				if(Plots[nPlots++] = new Function(this, data)){
+				if(Plots[nPlots++] = new Function(this, data, "Function")){
 					if(bRet = Plots[nPlots-1]->PropertyDlg())
 						memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
 					else {
@@ -4085,9 +4326,9 @@ PolarPlot::PropertyDlg()
 				Axes[1] = new Axis(this, data, &rad_axis, 
 					rad_axis.flags | AXIS_AUTOTICK | AXIS_NEGTICKS);
 				Axes[1]->SetSize(SIZE_LB_XDIST, 
-					NiceValue(-defs.GetSize(SIZE_AXIS_TICKS)*6.0)); 
+					NiceValue(-DefSize(SIZE_AXIS_TICKS)*6.0)); 
 				Axes[1]->SetSize(SIZE_TLB_XDIST, 
-					NiceValue(-defs.GetSize(SIZE_AXIS_TICKS)*2.0)); 
+					NiceValue(-DefSize(SIZE_AXIS_TICKS)*2.0)); 
 				Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
 				nAxes = 2;
 				bRet = true;
@@ -4106,7 +4347,6 @@ PolarPlot::PropertyDlg()
 bool
 BoxPlot::PropertyDlg()
 {
-	char text1[50], text2[50], text3[50], text4[50], text5[50], text6[50];
 	DlgInfo PlotDlg[] = {
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
 		{2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
@@ -4118,9 +4358,9 @@ BoxPlot::PropertyDlg()
 		{60, 61, 100, HIDDEN | ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{61, 0, 200, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{100, 102, 0, 0x0L, LTEXT, (void*)"range for grouping variable (X data)", 10, 39, 140, 9},
-		{102, 103, 0, 0x0L, RANGEINPUT, text1, 10, 49, 165, 10},
+		{102, 103, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
 		{103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 60, 90, 9},
-		{104, 150, 0, 0x0L, RANGEINPUT, text2, 10, 70, 165, 10},
+		{104, 150, 0, 0x0L, RANGEINPUT, TmpTxt+200, 10, 70, 165, 10},
 		{150, 160, 151, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 87, 165, 45},
 		{151, 152, 0, 0x0L, CHECKBOX, (void*)" line", 15, 92, 50, 9},
 		{152, 153, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 101, 50, 9},
@@ -4146,27 +4386,27 @@ BoxPlot::PropertyDlg()
 		{176, 177, 0, 0x0L, EDVAL1, &ci_err, 28, 203, 15, 10},
 		{177, 0, 0, 0x0L, LTEXT, (void*) "%  conf. interval", 45, 203, 70, 9},
 		{200, 202, 0, 0x0L, LTEXT, (void*)"range for common X values", 10, 39, 140, 9},
-		{202, 250, 0, 0x0L, RANGEINPUT, text1, 10, 49, 165, 10},
+		{202, 250, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
 		{250, 260, 251, ISPARENT | CHECKED, GROUPBOX, (void*) "                        ", 10, 68, 165, 30},
 		{251, 252, 0, 0x0L, CHECKBOX, (void*)" draw line", 15, 63, 50, 9},
 		{252, 253, 0, 0x0L, LTEXT, (void*)"range for line values", 15, 73, 80, 9},
-		{253, 0, 0, 0x0L, RANGEINPUT, text2, 15, 83, 155, 10},
+		{253, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 83, 155, 10},
 		{260, 270, 261, ISPARENT | CHECKED, GROUPBOX, (void*) "                               ", 10, 106, 165, 30},
 		{261, 262, 0, CHECKED, CHECKBOX, (void*)" draw symbols", 15, 101, 50, 9},
 		{262, 263, 0, 0x0L, LTEXT, (void*)"range for symbol values", 15, 111, 80, 9},
-		{263, 0, 0, 0x0L, RANGEINPUT, text2, 15, 121, 155, 10},
+		{263, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 121, 155, 10},
 		{270, 280, 271, ISPARENT | CHECKED, GROUPBOX, (void*) "                          ", 10, 144, 165, 50},
 		{271, 272, 0, CHECKED, CHECKBOX, (void*)" draw boxes", 15, 139, 50, 9},
 		{272, 273, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 149, 80, 9},
-		{273, 274, 0, 0x0L, RANGEINPUT, text3, 15, 159, 155, 10},
+		{273, 274, 0, 0x0L, RANGEINPUT, TmpTxt+300, 15, 159, 155, 10},
 		{274, 275, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 169, 80, 9},
-		{275, 0, 0, 0x0L, RANGEINPUT, text4, 15, 179, 155, 10},
+		{275, 0, 0, 0x0L, RANGEINPUT, TmpTxt+400, 15, 179, 155, 10},
 		{280, 0, 281, ISPARENT | CHECKED, GROUPBOX, (void*) "                              ", 10, 202, 165, 50},
 		{281, 282, 0, CHECKED, CHECKBOX, (void*)" draw whiskers", 15, 197, 50, 9},
 		{282, 283, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 207, 80, 9},
-		{283, 284, 0, 0x0L, RANGEINPUT, text5, 15, 217, 155, 10},
+		{283, 284, 0, 0x0L, RANGEINPUT, TmpTxt+500, 15, 217, 155, 10},
 		{284, 285, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 227, 80, 9},
-		{285, 0, 0, 0x0L, RANGEINPUT, text6, 15, 237, 155, 10},
+		{285, 0, 0, 0x0L, RANGEINPUT, TmpTxt+600, 15, 237, 155, 10},
 		{400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 223, 165, 30},
 		{401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 228, 70, 9},
 		{402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 228, 70, 9},
@@ -4175,21 +4415,19 @@ BoxPlot::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
-	int i, j, k, k1, l, l1, n, ic, c, res, width, height;
+	int i, j, k, k1, l, l1, n, ic, c, res, cb, width, height;
 	double x, y1, y2, dx, dy;
-	char errdesc[40];
+	char errdesc[40], boxdesc[40], symdesc[40];
 	lfPOINT fp1, fp2;
-	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
 		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
 	AccRange *rX = 0L, *rY1 = 0L, *rY2 = 0L;
-	int it_racc[] = {102, 104, 202, 253, 263, 273, 275, 283, 285};
 
 	if(!parent || !data) return false;
-	UseRangeMark(data, 1, text1, text2, text3, text4, text5, text6);
+	UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400, TmpTxt+500, TmpTxt+600);
 	ci_box = ci_err = 95.0;
-	if(!(Dlg = new DlgRoot(PlotDlg)))return false;
-	for(i=0; i < 9; i++) Dlg->ItemCmd(it_racc[i], CMD_SET_DATAOBJ, data);
-	text1[0] = text2[0] = 0;
+	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
+	TmpTxt[0] = TmpTxt[100] = 0;
 	hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 370, 550, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -4211,19 +4449,19 @@ BoxPlot::PropertyDlg()
 		}while (res <0);
 	if(res == 1) {
 		type = 0;				dirty = true;
-		if(Dlg->GetCheck(52) && Dlg->GetText(202, text1) && text1[0] &&(rX = new AccRange(text1))) {
-			xRange = strdup(text1);
+		if(Dlg->GetCheck(52) && Dlg->GetText(202, TmpTxt+100, 50) && TmpTxt[100] &&(rX = new AccRange(TmpTxt+100))) {
+			xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
 			n = rX->CountItems();	nPoints = n;
 			//  data line
-			if(n > 1 && Dlg->GetCheck(251) && Dlg->GetText(253, TmpTxt)) {
-				TheLine = new DataLine(this, data, text1, TmpTxt);
+			if(n > 1 && Dlg->GetCheck(251) && Dlg->GetText(253, TmpTxt, TMP_TXT_SIZE)) {
+				TheLine = new DataLine(this, data, TmpTxt+100, TmpTxt);
 				bRet = true;
 				}
 			// symbols
-			if(n > 0 && Dlg->GetCheck(261) && Dlg->GetText(263, TmpTxt) && TmpTxt[0] 
+			if(n > 0 && Dlg->GetCheck(261) && Dlg->GetText(263, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] 
 				&& (Symbols = (Symbol**)calloc(n, sizeof(Symbol*)))
 				&& (rY1 = new AccRange(TmpTxt))) {
-				yRange = strdup(TmpTxt);
+				yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);
 				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);
 				ic = c = 0;
@@ -4238,9 +4476,9 @@ BoxPlot::PropertyDlg()
 				if(ic) bRet = true;
 				}
 			// boxes
-			if(n > 0 && Dlg->GetCheck(271) && Dlg->GetText(273, text3) && Dlg->GetText(275, text4)
+			if(n > 0 && Dlg->GetCheck(271) && Dlg->GetText(273, TmpTxt+300, 50) && Dlg->GetText(275, TmpTxt+400, 50)
 				&& (Boxes = (Box**)calloc(n, sizeof(Box*)))
-				&& (rY1 = new AccRange(text3)) && (rY2 = new AccRange(text4))) {
+				&& (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
 				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);	rY2->GetFirst(&k1, &l1);
 				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);	rY2->GetNext(&k1, &l1);
 				ic = 0;
@@ -4255,9 +4493,9 @@ BoxPlot::PropertyDlg()
 				if(ic) bRet = true;
 				}
 			// whiskers
-			if(n > 0 && Dlg->GetCheck(281) && Dlg->GetText(283, text3) && Dlg->GetText(285, text4)
+			if(n > 0 && Dlg->GetCheck(281) && Dlg->GetText(283, TmpTxt+300, 50) && Dlg->GetText(285, TmpTxt+400, 50)
 				&& (Whiskers = (Whisker**)calloc(n, sizeof(Whisker*)))
-				&& (rY1 = new AccRange(text3)) && (rY2 = new AccRange(text4))) {
+				&& (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
 				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);	rY2->GetFirst(&k1, &l1);
 				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);	rY2->GetNext(&k1, &l1);
 				ic = 0;
@@ -4272,8 +4510,9 @@ BoxPlot::PropertyDlg()
 				}
 			if (bRet) Command(CMD_AUTOSCALE, 0L, 0L);
 			}
-		else if(Dlg->GetText(102, text1) && text1[0] && Dlg->GetText(104, text2) && text2[0]){
-			xRange = strdup(text1);				yRange = strdup(text2);
+		else if(Dlg->GetText(102, TmpTxt+100, 50) && TmpTxt[100] && Dlg->GetText(104, TmpTxt+200, 50) && TmpTxt[200]){
+			xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
+			yRange = (char*)memdup(TmpTxt+200, ((int)strlen(TmpTxt+200))+2, 0);
 			if(Dlg->GetCheck(154)) type |= 0x0001;		if(Dlg->GetCheck(155)) type |= 0x0002;
 			if(Dlg->GetCheck(156)) type |= 0x0003;		if(Dlg->GetCheck(157)) type |= 0x0004;
 			if(Dlg->GetCheck(161)) type |= 0x0010;		if(Dlg->GetCheck(162)) type |= 0x0020;
@@ -4285,43 +4524,75 @@ BoxPlot::PropertyDlg()
 			if(Dlg->GetCheck(151)) type |= 0x1000;		if(Dlg->GetCheck(152)) type |= 0x2000;
 			if(Dlg->GetCheck(401)) type |= 0x4000;		if(Dlg->GetCheck(402)) type |= 0x8000;
 			Dlg->GetValue(166, &ci_box);				Dlg->GetValue(176, &ci_err);
-			if(Dlg->GetText(404, TmpTxt) && TmpTxt[0]) case_prefix = strdup(TmpTxt);
+			if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 			CreateData();
 			if(curr_data && type) {
 				curr_data->GetSize(&width, &height);
-				sprintf(text1, "a1:a%d", height);	sprintf(text2, "b1:b%d", height);
+#ifdef USE_WIN_SECURE
+				sprintf_s(TmpTxt+100, 50, "a1:a%d", height);	sprintf_s(TmpTxt+200, 50, "b1:b%d", height);
+#else	
+				sprintf(TmpTxt+100, "a1:a%d", height);			sprintf(TmpTxt+200, "b1:b%d", height);
+#endif
 				nPoints = height;
 				if(nPoints > 1 && (type & 0x1000)) {
-					TheLine = new DataLine(this, curr_data, text1, text2);
+					TheLine = new DataLine(this, curr_data, TmpTxt+100, TmpTxt+200);
 					bRet = true;
 					}
 				if(nPoints > 0 && (type & 0x2000) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
+					switch(type & 0x000f) {
+					case 0x0001:	cb = rlp_strcpy(symdesc, 40, "Mean");				break;
+					case 0x0002:	cb = rlp_strcpy(symdesc, 40, "Geometric mean");		break;
+					case 0x0003:	cb = rlp_strcpy(symdesc, 40, "Harmonic mean");		break;
+					case 0x0004:	cb = rlp_strcpy(symdesc, 40, "Median");				break;
+					default:		cb = rlp_strcpy(symdesc, 40, "n.a.");				break;
+						}
 					for(i = 0; i < height; i++) {
 						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y1)
-							&& (Symbols[i] = new Symbol(this, curr_data, x, y1, SYM_PLUS, 0, i, 1, i)))
+							&& (Symbols[i] = new Symbol(this, curr_data, x, y1, SYM_PLUS, 0, i, 1, i))){
 							Symbols[i]->idx = i;
+							Symbols[i]->name = (char*)memdup(symdesc, cb+1, 0);
+							}
 						}
 					bRet = true;
 					}
 				if(nPoints > 0 && (type & 0x00f0) && (Boxes = (Box**)calloc(nPoints, sizeof(Box*)))) {
+					switch(type & 0x00f0) {
+					case 0x0010:	cb = rlp_strcpy(boxdesc, 40, "Std. Dev.");			break;
+					case 0x0020:	cb = rlp_strcpy(boxdesc, 40, "Std. Err.");			break;
+					case 0x0030:	cb = rlp_strcpy(boxdesc, 40, "25, 75% Perc.");		break;
+					case 0x0040:	cb = rlp_strcpy(boxdesc, 40, "Min./Max.");			break;
+#ifdef USE_WIN_SECURE
+					case 0x0500:	cb = sprintf_s(boxdesc, 40, "'%g%% CI", ci_err);	break;
+#else
+					case 0x0500:	cb = sprintf(boxdesc, "'%g%% CI", ci_err);			break;
+#endif
+					default:		cb = rlp_strcpy(boxdesc, 40, "n.a.");
+						}
 					for(i = 0; i < height; i++) {
 						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 2, &y1)
 							&&	curr_data->GetValue(i, 3, &y2)) {
 							fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
 							Boxes[i] = new Box(this, curr_data, fp1, fp2, BAR_RELWIDTH, 0, i, 2, i, 0, i, 3, i);
-							if(Boxes[i]) Boxes[i]->SetSize(SIZE_BOX, 60.0);
+							if(Boxes[i]){
+								Boxes[i]->SetSize(SIZE_BOX, 60.0);
+								Boxes[i]->name = (char*)memdup(boxdesc, cb+1, 0);
+								}
 							}
 						}
 					bRet = true;
 					}
 				if(nPoints > 0 && (type & 0x0f00) && (Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*)))) {
-					switch(type & 0x1f00) {
-					case 0x0100:	strcpy(errdesc, "Std. Dev.");			break;
-					case 0x0200:	strcpy(errdesc, "Std. Err.");			break;
-					case 0x0300:	strcpy(errdesc, "25, 75% Perc.");		break;
-					case 0x0400:	strcpy(errdesc, "Min./Max.");			break;
-					case 0x0500:	sprintf(errdesc, "'%g%% CI", ci_err);	break;
-					default:		strcpy(errdesc, "error");
+					switch(type & 0x0f00) {
+					case 0x0100:	rlp_strcpy(errdesc, 40, "Std. Dev.");			break;
+					case 0x0200:	rlp_strcpy(errdesc, 40, "Std. Err.");			break;
+					case 0x0300:	rlp_strcpy(errdesc, 40, "25, 75% Perc.");		break;
+					case 0x0400:	rlp_strcpy(errdesc, 40, "Min./Max.");			break;
+#ifdef USE_WIN_SECURE
+					case 0x0500:	sprintf_s(errdesc, 40, "'%g%% CI", ci_err);		break;
+#else
+					case 0x0500:	sprintf(errdesc, "'%g%% CI", ci_err);			break;
+#endif
+					default:		rlp_strcpy(errdesc, 40, "error");
 						}
 					for(i = 0; i < height; i++) {
 						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 4, &y1)
@@ -4334,7 +4605,7 @@ BoxPlot::PropertyDlg()
 					bRet = true;
 					}
 				if(nPoints > 0 && (type & 0xc000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
-					dy = -0.4 * defs.GetSize(SIZE_SYMBOL);
+					dy = -0.4 * DefSize(SIZE_SYMBOL);
 					if(type & 0x4000){
 						lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
 						dx = 0.0;
@@ -4402,8 +4673,7 @@ DensDisp::PropertyDlg()
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
 	UseRangeMark(data, 1, text1, text2);
-	if(!(Dlg = new DlgRoot(PlotDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
 	hDlg = CreateDlgWnd("Density profile", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -4432,16 +4702,16 @@ DensDisp::PropertyDlg()
 		case 1:
 			if(rX) delete rX;	if(rY) delete rY;
 			rX = rY = 0L;
-			if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
 			n = rX ? rX->CountItems() : 0;
 			if(!n) {
 				ErrorBox("direction range not specified\nor not valid.");
 				bContinue = true;
 				res = -1;
 				}
-			if(n && Dlg->GetText(103, TmpTxt) && (rY = new AccRange(TmpTxt))){
+			if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
 				if(n != rY->CountItems()) {
-					ErrorBox("both ranges must be given\nand must have same size");
+					ErrorBox("both ranges must be given\nand must have the same size");
 					bContinue = true;
 					res = -1;
 					}
@@ -4449,9 +4719,15 @@ DensDisp::PropertyDlg()
 			}
 		}while (res < 0);
 	if(res == 1 && n && rX && rY) {
+		if(Dlg->GetCheck(104)) {
+			y_info = rX->RangeDesc(data, 0);		x_info = rY->RangeDesc(data, 0);
+			}
+		else {
+			x_info = rX->RangeDesc(data, 0);		y_info = rY->RangeDesc(data, 0);
+			}
 		type = (bVert = Dlg->GetCheck(104)) ? align | 0x10 : align;
-		if(Dlg->GetText(101, TmpTxt)) xRange=strdup(TmpTxt);
-		if(Dlg->GetText(103, TmpTxt)) yRange=strdup(TmpTxt);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&DefLine, 0);
 		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&DefFill, 0);
 		if(DefFill.hatch) memcpy(&DefFillLine, DefFill.hatch, sizeof(LineDEF));
@@ -4475,23 +4751,22 @@ int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int
 
 	switch (res) {
 		case 1:
-			if(rX && nx && Dlg->GetText(101, TmpTxt) && TmpTxt[0] && 
+			if(rX && nx && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && 
 				(*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
 			else if(nx) *nx = 0;
-			if(Dlg->GetText(154, TmpTxt) && TmpTxt[0]) {
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
 				if(rd[0][*currYR]) free(rd[0][*currYR]);
-				rd[0][*currYR] = strdup(TmpTxt);
+				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 				}
 			break;
 		case 155:
 			res = -1;
 			*ny = 0;
 			if(rX) {
-				if(!(*currYR) && Dlg->GetText(101, TmpTxt) && TmpTxt[0]) {
+				if(!(*currYR) && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
 					if(*rX = new AccRange(TmpTxt)){
 						*nx = rX[0]->CountItems();
-						delete *rX;
-						*rX = 0L;
+						delete *rX;						*rX = 0L;
 						}
 					}
 				if(!(*nx)) {
@@ -4501,7 +4776,7 @@ int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int
 					break;
 					}
 				}
-			if(Dlg->GetText(154, TmpTxt) && TmpTxt[0]) {
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
 				if(*rY = new AccRange(TmpTxt)){
 					*ny = rY[0]->CountItems();
 					delete *rY;
@@ -4523,16 +4798,16 @@ int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int
 				rd[0][(*currYR)+1] = 0L;
 				}
 			if(rd[0][*currYR]) free(rd[0][*currYR]);
-			rd[0][*currYR] = strdup(TmpTxt);	//store y-ranges
+			rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);	//store y-ranges
 			*updateYR = true;
 			(*currYR)++;
 			Dlg->SetText(154, rd[0][*currYR]);
 			Dlg->Activate(154, true);
 			break;
 		case 156:
-			if(Dlg->GetText(154, TmpTxt)){
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE)){
 				if(rd[0][*currYR]) free(rd[0][*currYR]);
-				rd[0][*currYR] = strdup(TmpTxt);
+				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);;
 				}
 			else if(*currYR == *maxYR) (*maxYR)--;
 			(*currYR)--;
@@ -4581,7 +4856,7 @@ StackBar::PropertyDlg()
 	void *hDlg;
 	int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny;
 	bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
-	char **rd = 0L;
+	char **rd = 0L, *rname;
 	AccRange *rX = 0L, *rY = 0L;
 
 	if(!parent || !data) return false;
@@ -4589,12 +4864,12 @@ StackBar::PropertyDlg()
 		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
 	if(!(StackBarDlg = CompileDialog(StackBar_DlgTmpl, dyndata))) return false;
 	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
-		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) 
+			rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);	 maxYR = j-1;
 		}
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
-	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
+	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked Bar Plot" : 
 		(char*)"Stacked Polygons", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
@@ -4605,7 +4880,11 @@ StackBar::PropertyDlg()
 			else {
 				Dlg->ShowItem(156, false);				Dlg->Activate(101, true);
 				}
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(153, TmpTxt);
 			updateYR = false;
@@ -4613,8 +4892,7 @@ StackBar::PropertyDlg()
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		ny = 0;
-		if(rX) delete rX;
-		rX = 0L;
+		if(rX) delete rX;		rX = 0L;
 		switch(res) {
 		case 0:
 			if(bContinue || Dlg->GetCheck(20)) res = -1;
@@ -4634,39 +4912,55 @@ StackBar::PropertyDlg()
 	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]){	//accept settings and create plot
 		maxYR++;
 		for(i = j = 0; i < maxYR; i++) {
-			if(i) j += sprintf(TmpTxt+j, "&");
-			j += sprintf(TmpTxt+j, "%s", rd[i]);
+			if(i) TmpTxt[j++] = '&';
+			j+= rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, rd[i]);
 			}
-		ssYrange = strdup(TmpTxt);
-		if(Dlg->GetText(101, TmpTxt)) ssXrange = strdup(TmpTxt);
+		if(Dlg->GetCheck(204)) y_info = rX->RangeDesc(data, 0);
+		else x_info = rX->RangeDesc(data, 0);
+		ssYrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssXrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);;
 		cum_data_mode = Dlg->GetCheck(200) ? 1 : 2;
 		if(Id == GO_STACKPG) cum_data_mode += 2;
 		CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal);
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		//do stacked bar
+		if(rY)delete rY;	rY = 0L;
 		if(Id == GO_STACKBAR){
 			numPlots = maxYR;
 			if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*))) 
-				for(i = sc = 0; i < (maxYR); i++) {
-					if(Boxes[i]= new BoxPlot(this, CumData, Dlg->GetCheck(204)?2:1, 0, i+1, i+2)){
-					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);
-					Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+				for(i = sc = 0; i < (maxYR) && rd[i] && *rd[i]; i++) {
+					rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 1);
+					if(Boxes[i]= new BoxPlot(this, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
+					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);			Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
 					Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
 					Boxes[i]->SetSize(SIZE_BOX, 60.0);
+					if(rname) free(rname);	delete rY;	rY = 0L;
 					}
 				}
 			}
 		//do stacked polygon
 		else if(Id == GO_STACKPG){
-			numPG = maxYR;			sprintf(TmpTxt, "a1:a%d", nx*2);
-			if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))for(i=sc=0;i<maxYR;i++){
+			numPG = maxYR;
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, 20, "a1:a%d", nx*2);
+#else
+			sprintf(TmpTxt, "a1:a%d", nx*2);
+#endif
+			if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))
+				for(i=sc=0; i < maxYR && rd[i] && *rd[i];i++){
+#ifdef USE_WIN_SECURE
+				sprintf_s(TmpTxt+20, 20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
+#else
 				sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
-				if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt);
-				else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20);
+#endif
+				rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 1);
+				if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt, rname);
+				else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20, rname);
 				if(Polygons[i]) {
 					Polygons[i]->Command(CMD_AUTOSCALE, 0L, 0L);
 					Polygons[i]->Command(CMD_PG_FILL, GetSchemeFill(&sc), 0L);
 					}
+				if(rname) free(rname);	delete rY;	rY = 0L;
 				}
 			}
 		if(Bounds.Xmax >= Bounds.Xmin && Bounds.Ymax >= Bounds.Ymin) bRet = true;
@@ -4727,7 +5021,7 @@ GroupBars::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false, updateYR = true, bContinue = false;
-	char **rd = 0L;
+	char **rd = 0L, *desc;
 	Bar **bars = 0L;
 	AccRange *rY = 0L;
 	int i, j, ic, res, ix, iy, ny, sc = 0, currYR = 0, maxYR = 0;
@@ -4739,20 +5033,24 @@ GroupBars::PropertyDlg()
 	if(!(GBDlg = CompileDialog(GBDlg_Tmpl, dyndata)))return false;
 	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
 		for(i=0, j= 0; i <= 1000; i +=100) 
-			if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+			if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
+			maxYR = j-1;
 		}
 	Id = GO_STACKBAR;
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
-	if(!(Dlg = new DlgRoot(GBDlg)))return false;
+	if(!(Dlg = new DlgRoot(GBDlg, data)))return false;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	else Dlg->SetText(154, "");
-	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Grouped bar chart", 50, 50, 370, 240, Dlg, 0x0L);
 	do {
 		if(updateYR) {
 			if(currYR >0) Dlg->ShowItem(156, true);
 			else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(153, TmpTxt);
 			updateYR = false;
@@ -4789,18 +5087,19 @@ GroupBars::PropertyDlg()
 			}
 		xinc = fabs(step / ((double)maxYR + gg/100.0));
 		start -= (xinc * ((double)maxYR-1))/2.0;
-		for(i = 0; i < maxYR; i++) {
+		for(i = 0, desc = 0L; i < maxYR; i++) {
 			x = start + xinc * (double)i;
 			if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
 			else {
 				rY = 0L;	ny = 0;
 				}
+			desc = rY->RangeDesc(data, 1);
 			rY->GetFirst(&ix, &iy);				rY->GetNext(&ix, &iy);
 			if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
 				for(ic = 0; ic < ny; ic++) {
 					if(data->GetValue(iy, ix, &y)){
 						bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
-							-1, -1, ix, iy);
+							-1, -1, ix, iy, desc);
 						CheckBounds(x, y);
 						}
 					x += step;
@@ -4813,11 +5112,9 @@ GroupBars::PropertyDlg()
 					xyPlots[i]->Command(CMD_BAR_FILL, GetSchemeFill(&sc), 0L);
 					}
 				for(ic = 0; ic < ny; ic++) if(bars[ic]) delete(bars[ic]);
-				free(bars);
-				bRet = true;
+				free(bars);			bRet = true;
 				}
-			if(rY) delete(rY);
-			rY = 0L;
+			if(rY) delete(rY);		if(desc) free(desc);		rY = 0L;
 			}
 		}
 	CloseDlgWnd(hDlg);
@@ -4865,16 +5162,16 @@ Waterfall::PropertyDlg()
 		{204, 205, 0, 0x0L, EDVAL1, &dspm.fy, 88, 45, 25, 10},
 		{205, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 45, 15, 8}, 
 		{300, 301, 0, CHECKED, RADIO1, (void*)" common color for lines:", 20, 35, 80, 9},
-		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 105, 35, 20, 10},
+		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&defcol, 105, 35, 20, 10},
 		{302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
-		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
-		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
-		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
-		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
-		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
-		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
-		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
-		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
+		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[0], 25, 70, 10, 10},
+		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[1], 37, 70, 10, 10},
+		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[2], 49, 70, 10, 10},
+		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[3], 61, 70, 10, 10},
+		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[4], 73, 70, 10, 10},
+		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[5], 85, 70, 10, 10},
+		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[6], 97, 70, 10, 10},
+		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[7], 109, 70, 10, 10},
 		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
 	DlgRoot *Dlg;
 	void *hDlg;
@@ -4887,24 +5184,27 @@ Waterfall::PropertyDlg()
 	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
 		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
 	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
-		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) 
+			rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
+			maxYR = j-1;
 		}
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
-	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
+	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create waterfall plot", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
 			if(currYR >0) {
-				Dlg->ShowItem(156, true);
-				Dlg->Activate(101, false);
+				Dlg->ShowItem(156, true);				Dlg->Activate(101, false);
 				}
 			else {
-				Dlg->ShowItem(156, false);
-				Dlg->Activate(101, true);
+				Dlg->ShowItem(156, false);				Dlg->Activate(101, true);
 				}
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(153, TmpTxt);
 			updateYR = false;
@@ -4943,7 +5243,7 @@ Waterfall::PropertyDlg()
 		maxYR++;
 		numPL = maxYR;
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-		Dlg->GetText(101, text1);
+		Dlg->GetText(101, text1, 100);
 		if(Lines=(DataLine**)calloc(numPL,sizeof(DataLine*)))for(i=0;i<maxYR;i++){
 			if(rd[i] && rd[i][0]) Lines[i] = new DataLine(this, data, text1, rd[i]);
 			if(Lines[i]) {
@@ -5025,12 +5325,11 @@ MultiLines::PropertyDlg()
 	if(TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*))) 
 		&& (rdy = (char**)calloc(12, sizeof(char*))) && (rdc = (DWORD*)malloc(12*sizeof(DWORD)))) {
 		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) {
-			rdx[j] = strdup(TmpTxt);		rdc[j] = colarr[j%8];	
-			rdy[j] = strdup(TmpTxt+i);		maxYR = j++;
+			rdx[j] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);			rdc[j] = colarr[j%8];	
+			rdy[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);		maxYR = j++;
 			}
 		}
-	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
-	Dlg->ItemCmd(102, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(104, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
 	hDlg = CreateDlgWnd("Create Multi Line Plot", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
@@ -5040,10 +5339,18 @@ MultiLines::PropertyDlg()
 			else {
 				Dlg->ShowItem(106, false);	Dlg->ShowItem(108, true);
 				}
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "x-range # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"x-range # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(101, TmpTxt);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-range # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-range # %d/%d", currYR+1, maxYR+1);
+#endif
 			Dlg->SetText(103, TmpTxt);
 			updateYR = false;
 			}
@@ -5059,7 +5366,7 @@ MultiLines::PropertyDlg()
 		case 1:
 		case 105:										//next button
 			bError=false;	s1 = s2 = 0;
-			if(Dlg->GetText(102, x_txt)) {
+			if(Dlg->GetText(102, x_txt, 100)) {
 				if(rX = new AccRange(x_txt)) {
 					s1 = rX->CountItems();
 					if(s1 < 2) {
@@ -5072,7 +5379,7 @@ MultiLines::PropertyDlg()
 				else bError = true;
 				}
 			else bError = true;
-			if(Dlg->GetText(104, y_txt) && !bError) {
+			if(Dlg->GetText(104, y_txt, 100) && !bError) {
 				if(rY = new AccRange(y_txt)) {
 					s2 = rY->CountItems();
 					if(s2 < 2) {
@@ -5103,10 +5410,10 @@ MultiLines::PropertyDlg()
 					maxYR = currYR+1;
 					rdc[currYR] = rdc[currYR+1] = Dlg->GetCheck(302) ? colarr[maxYR & 0x07] : defcol;
 					}
-				if(rdx[currYR]) free(rdx[currYR]);
-				rdx[currYR] = strdup(x_txt);			//store x-range
-				if(rdy[currYR]) free(rdy[currYR]);
-				rdy[currYR] = strdup(y_txt);			//store y-range
+				if(rdx[currYR]) free(rdx[currYR]);		//store x-range
+				rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
+				if(rdy[currYR]) free(rdy[currYR]);		//store y range
+				rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
 				Dlg->GetColor(107, &curr_col);			rdc[currYR] = curr_col;
 				updateYR = true;						currYR++;
 				Dlg->SetColor(107, rdc[currYR]);		Dlg->SetText(102, rdx[currYR]);
@@ -5119,9 +5426,10 @@ MultiLines::PropertyDlg()
 				}
 			break;
 		case 106:										//prev button
-			if(Dlg->GetText(102, x_txt) && Dlg->GetText(104, y_txt)){
-				if(rdx[currYR]) free(rdx[currYR]);		rdx[currYR] = strdup(x_txt);
-				if(rdy[currYR]) free(rdy[currYR]);		rdy[currYR] = strdup(y_txt);
+			if(Dlg->GetText(102, x_txt, 100) && Dlg->GetText(104, y_txt, 100)){
+				if(rdx[currYR]) free(rdx[currYR]);		if(rdy[currYR]) free(rdy[currYR]);
+				rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
+				rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
 				Dlg->GetColor(107, &curr_col);			rdc[currYR] = curr_col;
 				}
 			else if(currYR == maxYR) maxYR--;
@@ -5196,12 +5504,12 @@ static char *PieDlgTmpl =
 		"6,10,300,ISPARENT,SHEET,3,5,10,120,103\n"
 		"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
 		"100,101,,,LTEXT,4,10,25,60,8\n"
-		"101,105,,,RANGEINPUT,5,15,35,100,10\n"
+		"101,105,,,RANGEINPUT,-15,15,35,100,10\n"
 		"105,106,500,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
 		"106,107,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
 		"107,108,,,EDVAL1,6,58,59,30,10\n"
 		"108,,,,LTEXT,-3,89,59,15,8\n" 
-		"200,,,,LTEXT,7,15,30,60,8\n"
+		"200,201,,,LTEXT,7,15,30,60,8\n"
 		"201,202,,,RTEXT,-4,2,42,20,8\n"
 		"202,204,,,EDVAL1,8,23,42,30,10\n"
 		"204,205,,,RTEXT,-5,47,42,20,8\n"
@@ -5220,7 +5528,7 @@ static char *PieDlgTmpl =
 		"411,,,EXRADIO,ODBUTTON,15,70,75,30,30\n"
 		"500,501,,CHECKED,RADIO1,16,10,59,20,8\n"
 		"501,502,,,RADIO1,17,10,71,40,8\n"
-		"502,503,,,RANGEINPUT,18,15,82,100,10\n"
+		"502,503,,,RANGEINPUT,-16,15,82,100,10\n"
 		"503,504,,,LTEXT,19,15,94,10,8\n"
 		"504,505,,,EDVAL1,20,42,94,25,10\n"
 		"505,,,,LTEXT,21,70,94,15,8\n"
@@ -5237,15 +5545,15 @@ PieChart::PropertyDlg()
 	double fcx =10.0, fcy = 20.0, frad=40.0, firad = 30.0;
 	char txt2[80];
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"spread sheet range for values",
-		(void*)TmpTxt, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
+		0L, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
 		(void*)"start angle", (void*)&CtDef.fx, (void*)"degree", (void*)"style:", (void*)(OD_scheme),
 		(void*)(OD_PieTempl), (void*)"fixed radius", (void*)"pick radii from spreadsheet range",
-		(void*)(TmpTxt+100), (void*)"x  factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
+		0L, (void*)"x  factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
 		(void*)"inner radius", (void*)&firad};
 	DlgInfo *PieDlg = CompileDialog(PieDlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, ix, iy, rix, riy, ny, res, cf;
+	int i, ix, iy, rix, riy, ny, res, cf, cb;
 	bool bRet = false, bContinue = false;
 	double sum = 0.0, dang1, dang2;
 	double fv;
@@ -5254,13 +5562,13 @@ PieChart::PropertyDlg()
 
 	if(!parent || !data) return false;
 	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
-	sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+	cb = rlp_strcpy(txt2, 80, "= [");	cb += rlp_strcpy(txt2+cb, 80-cb, Units[defs.cUnits].display);
+	rlp_strcpy(txt2+cb, 80-cb, "]");
 	frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0;
 	fcx = parent->GetSize(SIZE_GRECT_LEFT) + (parent->GetSize(SIZE_DRECT_LEFT))/2.0 + frad;
 	fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
 	firad = frad-frad/10.0f;
-	if(!(Dlg = new DlgRoot(PieDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(502, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(PieDlg, data)))return false;
 	if(Id == GO_PIECHART) {
 		Dlg->ShowItem(105, true);		Dlg->ShowItem(106, false);
 		Dlg->ShowItem(210, true);		Dlg->ShowItem(211, false);
@@ -5270,7 +5578,7 @@ PieChart::PropertyDlg()
 		Dlg->ShowItem(210, false);		Dlg->ShowItem(211, true);
 		}
 	hDlg = CreateDlgWnd(Id == GO_PIECHART ? (char*)"Create pie chart" : 
-		(char*)"Create ring chart",	50, 50, 370, 260, Dlg, 0x0L);
+		(char*)"Create ring chart",	50, 50, 370, 266, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -5292,13 +5600,13 @@ PieChart::PropertyDlg()
 			CtDef.fy = 180.0;					res = -1;
 			break;
 		case 1:
-			if(Dlg->GetText(101, TmpTxt) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
 				ny = rY->CountItems();
 			else ny = 0;
 			Dlg->GetValue(208, &CtDef.fx);		Dlg->GetValue(202, &fcx);
 			Dlg->GetValue(205, &fcy);			Dlg->GetValue(107, &frad);
 			Dlg->GetValue(602, &firad);			Dlg->GetValue(504, &FacRad);
-			if(Dlg->GetCheck(501) && ny && Dlg->GetText(502, TmpTxt) && 
+			if(Dlg->GetCheck(501) && ny && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE) && 
 				(rR = new AccRange(TmpTxt))){
 				if(rR->CountItems() != ny) {
 					delete rR;
@@ -5315,8 +5623,8 @@ PieChart::PropertyDlg()
 
 	if(res == 1 && rY && ny >1 && (Segments = (segment **)calloc(ny, sizeof(segment*)))) {
 		nPts = ny;
-		if(Dlg->GetText(101, TmpTxt)) ssRefA = strdup(TmpTxt);
-		if(rR && Dlg->GetText(502, TmpTxt)) ssRefR = strdup(TmpTxt);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssRefA = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+		if(rR && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE)) ssRefR = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 		Bounds.Xmax = Bounds.Ymax = 100.0;		Bounds.Xmin = Bounds.Ymin = -100.0;
 		fpCent.fx = fcx;					fpCent.fy = fcy;
 		rY->GetFirst(&ix, &iy);				rY->GetNext(&ix, &iy);
@@ -5359,7 +5667,7 @@ StarChart::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 25, 10, "Data"};
 	TabSHEET tab2 = {25, 55, 10, "Labels"};
-	double sa = 90.0, factor = 1.0, lbdist = NiceValue(defs.GetSize(SIZE_TEXT)*1.2);
+	double sa = 90.0, factor = 1.0, lbdist = NiceValue(DefSize(SIZE_TEXT)*1.2);
 	char txt1[80], txt2[80];
 	DlgInfo StarDlg[] = {
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
@@ -5394,20 +5702,22 @@ StarChart::PropertyDlg()
 	double fx, fy, tmpval, frad;
 	double sia, csia;
 	polyline *plo;
-	TextDEF td = {0x00000000L, 0x00ffffffL, defs.GetSize(SIZE_TEXT), 0.0, 0.0, 0,
+	TextDEF td = {0x00000000L, 0x00ffffffL, DefSize(SIZE_TEXT), 0.0, 0.0, 0,
 		TXA_HCENTER | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L}; 
 
 	if(!parent || !data) return false;
 	data->GetSize(&width, &height);
-	sprintf(txt1, "a1:a%d", height);
-	sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+#ifdef USE_WIN_SECURE
+	sprintf_s(txt1, 80,"a1:a%d", height);	sprintf_s(txt2, 80, "= [%s]", Units[defs.cUnits].display);
+#else
+	sprintf(txt1, "a1:a%d", height);		sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+#endif
 	if(parent) {
 		frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
 		fPos.fx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT) + frad;
 		fPos.fy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
 		}
-	if(!(Dlg = new DlgRoot(StarDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(201, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(StarDlg, data)))return false;
 	hDlg = CreateDlgWnd("Create star chart", 50, 50, 370, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -5421,7 +5731,7 @@ StarChart::PropertyDlg()
 			bContinue = false;
 			break;
 		case 1:
-			if(Dlg->GetText(101, TmpTxt) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
 				ny = rY->CountItems();
 			else ny = 0;
 			Dlg->GetValue(106, &sa);			Dlg->GetValue(103, &factor);
@@ -5461,7 +5771,7 @@ StarChart::PropertyDlg()
 					}
 				}
 			}
-		if(Dlg->GetCheck(200) && Dlg->GetText(201, TmpTxt) && TmpTxt[0] && (rL = new AccRange(TmpTxt))){
+		if(Dlg->GetCheck(200) && Dlg->GetText(201, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rL = new AccRange(TmpTxt))){
 			rL->GetFirst(&ix, &iy);
 			td.text = TmpTxt;
 			for(i = 0; i < ny; i++) {
@@ -5509,13 +5819,13 @@ Grid3D::Configure()
 		{401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 20, 25, 10},
 		{402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 20, 20, 8},
 		{403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 32, 40, 8},
-		{404, 405, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 80, 32, 25, 10},
+		{404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 32, 25, 10},
 		{405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 44, 40, 8},
 		{406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 44, 25, 10},
 		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 15, 130, 100}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, new_type, undo_level = *Undo.pcb;
+	int res, cb, new_type, undo_level = *Undo.pcb;
 	bool bRet = false;
 	double tmp;
 	DWORD new_col;
@@ -5525,15 +5835,18 @@ Grid3D::Configure()
 	if(!parent) return false;
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	if(!(Dlg = new DlgRoot(GridDlg))) return false;
+	if(!(Dlg = new DlgRoot(GridDlg, data))) return false;
 	if(!type) {
 		Dlg->ShowItem(300, true);	Dlg->SetCheck(305, 0L, true);
 		}
 	else {
 		Dlg->ShowItem(301, true);	Dlg->SetCheck(306, 0L, true);
 		}
-	if(parent->name) sprintf(TmpTxt, "Grid of %s", parent->name);
-	else strcpy(TmpTxt, "3D Grid");
+	if(parent->name) {
+		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Grid of ");
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+		}
+	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Grid");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 426, 260, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -5650,7 +5963,7 @@ Scatt3D::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, n1, n2, n3, ic = 0;
-	int i, j, k, l, m, n, i2, j2, k2, l2, m2;
+	int i, j, k, l, m, n, i2, j2, k2, l2, m2, cb;
 	double x, y, z, bar_w, bar_d, rad;
 	bool bRet = false, bContinue = false;
 	AccRange *rX, *rY, *rZ;
@@ -5658,16 +5971,14 @@ Scatt3D::PropertyDlg()
 
 	if(!data || !parent)return false;
 	UseRangeMark(data, 1, text1, text2, text3);
-	if(!(Dlg = new DlgRoot(Dlg3D)))return false;
+	if(!(Dlg = new DlgRoot(Dlg3D, data)))return false;
 	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(105, CMD_SET_DATAOBJ, data);
 	for(i = 0; i < 5; i++) Dlg->SetCheck(201+i, 0L, (c_flags & (1<<i))!=0);
 	if(c_flags == 0x2000 || c_flags == 0x4000) {
 		Dlg->ShowItem(5, false);		Dlg->ShowItem(6, false);
 		}
 	else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
-	rX = rY = rZ = 0L;					rad = defs.GetSize(SIZE_SYMBOL);
+	rX = rY = rZ = 0L;					rad = DefSize(SIZE_SYMBOL);
 #ifdef _WINDOWS
 	for(i = 61; i <= 62; i++) Dlg->TextSize(i, 12);
 #else
@@ -5700,9 +6011,9 @@ Scatt3D::PropertyDlg()
 		case 1:
 			if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
 			rX = rY = rZ = 0L;	n1 = n2 = n3 = 0;
-			if(Dlg->GetText(101, text1) && (rX = new AccRange(text1))) n1 = rX->CountItems();
-			if(Dlg->GetText(103, text2) && (rY = new AccRange(text2))) n2 = rY->CountItems();
-			if(Dlg->GetText(105, text3) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
+			if(Dlg->GetText(101, text1, 100) && (rX = new AccRange(text1))) n1 = rX->CountItems();
+			if(Dlg->GetText(103, text2, 100) && (rY = new AccRange(text2))) n2 = rY->CountItems();
+			if(Dlg->GetText(105, text3, 100) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
 			if(n1 && n2 && n3){
 				if(c_flags == 0x2000 || c_flags == 0x4000) {
 					//no more but a ribbon ore surface
@@ -5718,9 +6029,11 @@ Scatt3D::PropertyDlg()
 					}
 				}
 			else {
-				sprintf(TmpTxt, "Ranges for\n%s%s%s\n\nnot given or not valid.",
-					n1 == 0 ? "\n  X Data" : "", n2 == 0 ? "\n  Y Data" : "",
-					n3 == 0 ? "\n  Z Data" : "");
+				cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ranges for ");
+				if(!n1) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  X Data");
+				if(!n2) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  Y Data");
+				if(!n3) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  Z Data");
+				rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\nnot given or not valid.");
 				InfoBox(TmpTxt);
 				res = -1;	bContinue = true;
 				}
@@ -5731,7 +6044,7 @@ Scatt3D::PropertyDlg()
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
 		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
-		bar_w = bar_d = (defs.GetSize(SIZE_BAR)/2.0);
+		bar_w = bar_d = (DefSize(SIZE_BAR)/2.0);
 		if(c_flags & 0x01) (Balls = (Sphere**)calloc((nBalls = n1)+1, sizeof(Sphere*)));
 		if(c_flags & 0x02) (Columns = (Brick**)calloc((nColumns = n1)+1, sizeof(Brick*)));
 		if(c_flags & 0x04) Line = new Line3D(this, data, text1, text2, text3);
@@ -5743,11 +6056,10 @@ Scatt3D::PropertyDlg()
 		i2 = i;	j2 = j;	k2 = k;	l2 = l;	m2 = m;	n2 = n;
 		if(c_flags == 0x2000){
 			Bounds.Ymin = 0.0;
-			rib = new Ribbon(this, data, text1, text2, text3);
+			rib = new Ribbon(this, data, 2, text1, text2, text3);
 			}
 		else if(c_flags == 0x4000){
-			Bounds.Ymin = 0.0;
-			rib = SurfTria(this, data, text1, text2, text3);
+			rib = new Ribbon(this, data, 3, text1, text2, text3);
 			}
 		do {
 			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && 
@@ -5818,7 +6130,7 @@ Function::PropertyDlg()
 	if(!parent) return false;
 	if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
 	if(!bNew) Dlg->ShowItem(10, false);
 	Dlg->GetValue(102, &o_x1);		n_x1 = o_x1;
 	Dlg->GetValue(104, &o_x2);		n_x2 = o_x2;
@@ -5840,9 +6152,9 @@ Function::PropertyDlg()
 		if(bNew) {						//create function
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
-			Dlg->GetValue(106, &xstep);		Dlg->GetText(200, TmpTxt);
-			cmdxy = strdup(TmpTxt);			ReshapeFormula(&cmdxy);
-			bRet = Update(0L, 0L);
+			Dlg->GetValue(106, &xstep);		Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
+			cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+			ReshapeFormula(&cmdxy);			bRet = Update(0L, 0L);
 			}
 		else {							//edit existing function
 			Dlg->GetValue(102, &n_x1);		Dlg->GetValue(104, &n_x2);
@@ -5850,10 +6162,11 @@ Function::PropertyDlg()
 			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
 			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
 			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
-			Dlg->GetText(200, TmpTxt);
+			Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
 			if(cmdxy && strcmp(cmdxy, TmpTxt)) {
 				Undo.String(this, &cmdxy, undo_flags);
-				free(cmdxy);	cmdxy = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
+				free(cmdxy);				undo_flags |= UNDO_CONTINUE;
+				cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 				}
 			if(undo_flags & UNDO_CONTINUE){
 				Update(0L, UNDO_CONTINUE);
@@ -5920,6 +6233,7 @@ FitFunc::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, undo_level = *Undo.pcb, i, j, k, l, cs;
+	size_t cb;
 	bool bRet = false, bContinue = false;
 	DWORD undo_flags = 0L;
 	LineDEF newLine;
@@ -5930,19 +6244,22 @@ FitFunc::PropertyDlg()
 	anyResult *ares;
 
 	if(!parent || !data) return false;
-	if(!(o_cmdxy = strdup(cmdxy))) return false;
-	if(!(o_parxy = strdup(parxy))) return false;
+	if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0))) return false;;
+	if(!(o_parxy = (char*)memdup(parxy, (int)strlen(parxy)+1, 0))) return false;;
 	UseRangeMark(data, 1, text1, text2);
 	iter = (double)maxiter;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
-	Dlg->ItemCmd(401, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(403, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
 	if(!bNew){
 		Dlg->ShowItem(10, false);		Dlg->Activate(401, false);
 		Dlg->Activate(403, false);		Dlg->SetCheck(6, 0L, true);
 		Dlg->SetCheck(4, 0L, false);	Dlg->ShowItem(404, false);
 		if(chi2 > 0.0) {
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
+#else
 			sprintf(TmpTxt, "Chi 2 = %g", chi2);
+#endif
 			Dlg->SetText(405,TmpTxt);	Dlg->ShowItem(405, true);
 			}
 		}
@@ -5965,11 +6282,13 @@ FitFunc::PropertyDlg()
 			break;
 		case 1:
 			if(!bNew){
-				if(Dlg->GetText(102, TmpTxt) && parxy) {
-					free(parxy);	parxy = strdup(TmpTxt);
+				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+					if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
+						rlp_strcpy(parxy, (int)cb, TmpTxt);
 					}
-				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
-					free(cmdxy);	cmdxy = strdup(TmpTxt);
+				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+					if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
+						rlp_strcpy(cmdxy, (int)cb, TmpTxt);
 					}
 				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
 				dirty = true;
@@ -5979,12 +6298,14 @@ FitFunc::PropertyDlg()
 			Undo.SetDisp(cdisp);
 			if(Dlg->GetCheck(5)) {			//  the function tab must be shown
 				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
-				Dlg->GetText(401, text1);		Dlg->GetText(403, text2);
-				if(Dlg->GetText(102, TmpTxt) && parxy) {
-					free(parxy);	parxy = strdup(TmpTxt);
+				Dlg->GetText(401, text1, 100);		Dlg->GetText(403, text2, 100);
+				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+					if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
+						rlp_strcpy(parxy, (int)cb, TmpTxt);
 					}
-				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
-					free(cmdxy);	cmdxy = strdup(TmpTxt);
+				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+					if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
+						rlp_strcpy(cmdxy, (int)cb, TmpTxt);
 					}
 				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
 				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
@@ -6000,10 +6321,22 @@ FitFunc::PropertyDlg()
 					bContinue = true;	res = -1;
 					break;
 					}
+				i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, parxy);	i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;");
+				rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy);	yywarn(0L, true);
+				ares = do_formula(data, TmpTxt);
+				if(tmp_char = yywarn(0L, false)) {
+					ErrorBox(tmp_char);
+					bContinue = true;	res = -1;
+					break;
+					}
 				i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
 				Dlg->SetText(102, parxy);
 				if(i >1 || res == 7) {
+#ifdef USE_WIN_SECURE
+					sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#else
 					sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#endif
 					InfoBox(TmpTxt);
 					}
 				bContinue = true;
@@ -6022,9 +6355,10 @@ FitFunc::PropertyDlg()
 	if(res == 1){						//OK pressed
 		//get ranges for x- and y data (again).
 		chi2 = n_chi2;
-		Dlg->GetText(401, text1);		Dlg->GetText(403, text2);
-		if(ssXref) free(ssXref);		if(ssYref) free(ssYref);
-		ssXref = strdup(text1);			ssYref = strdup(text2);
+		if(Dlg->GetText(401, text1, 100) && (ssXref = (char*)realloc(ssXref, (cb = strlen(text1)+2))))
+			rlp_strcpy(ssXref, (int)cb, text1);
+		if(Dlg->GetText(403, text2, 100) && (ssYref = (char*)realloc(ssYref, (cb = strlen(text2)+2))))
+			rlp_strcpy(ssYref, (int)cb, text2);
 		if(bNew) {						//create function
 			if(!(rX = new AccRange(text1)) || ! (rY = new AccRange(text2))) return false;
 			i = rX->CountItems();	maxiter = int(iter);
@@ -6042,7 +6376,7 @@ FitFunc::PropertyDlg()
 					}
 				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
 			delete rX;	delete rY;
-			if(x1 >= x2 || !(dl = new Function(this, data))){
+			if(x1 >= x2 || !(dl = new Function(this, data, "Fitted function"))){
 				CloseDlgWnd(hDlg);
 				delete Dlg;
 				return false;
@@ -6127,7 +6461,7 @@ Plot3D::AddPlot(int family)
 	bool bRet = false;
 	Plot *p;
 
-	if(!(Dlg = new DlgRoot(PlotsDlg)))return false;
+	if(!(Dlg = new DlgRoot(PlotsDlg, data)))return false;
 	hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 204, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -6249,12 +6583,14 @@ Chart25D::PropertyDlg()
 	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
 		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
 	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
-		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		for(i=100, j= 0; i <= 1000; i +=100){ 
+			if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
+			}
+		if(j) maxYR = j-1;
 		}
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
-	if(!(Dlg = new DlgRoot(Bar3D_Dlg))) return false;
+	if(!(Dlg = new DlgRoot(Bar3D_Dlg, data))) return false;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create 3D Bar Chart", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
@@ -6266,7 +6602,11 @@ Chart25D::PropertyDlg()
 				Dlg->ShowItem(156, false);
 				Dlg->Activate(101, true);
 				}
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(153, TmpTxt);
 			updateYR = false;
@@ -6303,7 +6643,7 @@ Chart25D::PropertyDlg()
 		}while (res < 0);
 	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
 		if(rd[maxYR]) maxYR++;
-		fsz = defs.GetSize(SIZE_BAR)/2.0;	fz = start_z;
+		fsz = DefSize(SIZE_BAR)/2.0;	fz = start_z;
 		oax = AxisTempl3D;	AxisTempl3D = 1;	CreateAxes();
 		if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
 			ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
@@ -6376,7 +6716,7 @@ Ribbon25D::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, j, res, currYR=0, maxYR=0, nx=0, ny, oax;
-	char **rd = 0L;
+	char **rd = 0L, xrange[100];
 	double fz;
 	bool updateYR = true, bContinue = false, bRet = false, bUseSch;
 	AccRange *rX = 0L, *rY = 0L;
@@ -6391,12 +6731,14 @@ Ribbon25D::PropertyDlg()
 	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
 		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
 	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
-		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		for(i=100, j= 0; i <= 1000; i +=100){ 
+			if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
+			}
+		if(j) maxYR = j-1;
 		}
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
-	if(!(Dlg = new DlgRoot(Bar3D_Dlg)))return false;
+	if(!(Dlg = new DlgRoot(Bar3D_Dlg, data)))return false;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create 3D Ribbon Chart", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
@@ -6406,7 +6748,11 @@ Ribbon25D::PropertyDlg()
 			else {
 				Dlg->ShowItem(156, false);		Dlg->Activate(101, true);
 				}
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
 			//SetText will also cause a redraw of the whole dialog
 			Dlg->SetText(153, TmpTxt);
 			updateYR = false;
@@ -6440,21 +6786,23 @@ Ribbon25D::PropertyDlg()
 		}while (res < 0);
 	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
 		if(rd[maxYR]) maxYR++;					fz = start_z;
+		Dlg->GetText(101, TmpTxt+100, 100);
 		oax = AxisTempl3D;	AxisTempl3D = 1;	CreateAxes();
-		Dlg->GetText(101, TmpTxt+100);
 		if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
 			ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
 			ax->min = start_z-dspm.fz;
 			ax->max = start_z+dspm.fz*maxYR;
 			if(Axes[1] && (ax = Axes[1]->GetAxis())){
-				ax->flags |= AXIS_GRIDLINE;				i = 0x0c;
+				ax->flags |= AXIS_GRIDLINE;	
+				i = 0x0c;
 				Axes[1]->Command(CMD_SET_GRIDTYPE, &i, 0L);
 				}
 			AxisTempl3D = oax;
 			}
 		if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
+			Dlg->GetText(101, xrange, 100);
 			for(i = 0; i < maxYR; i++, fz += dspm.fz) {
-				if(plot = new Ribbon(this, data, fz, dspm.fz, TmpTxt+100, rd[i])){
+				if(plot = new Ribbon(this, data, fz, dspm.fz, xrange, rd[i])){
 					if(bUseSch) plot->SetColor(COL_POLYGON, colarr[(i & 0x07)]);
 					else plot->SetColor(COL_POLYGON, defcol);
 					plots[nPlots++] = plot;
@@ -6519,12 +6867,10 @@ BubblePlot3D::PropertyDlg()
 	Sphere **Balls;
 	AccRange *rX, *rY, *rZ, *rR;
 	Scatt3D *sc_plot;
-	int etracc[] = {101, 103, 105, 151};
 
 	if(!data || !parent)return false;
 	UseRangeMark(data, 1, text1, text2, text3, text4);
-	if(!(Dlg = new DlgRoot(BubDlg3D)))return false;
-	for(i = 0; i < 4; i++) Dlg->ItemCmd(etracc[i], CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(BubDlg3D, data)))return false;
 	rX = rY = rZ = rR = 0L;
 	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
 	hDlg = CreateDlgWnd("Bubble Plot 3D", 50, 50, 388, 340, Dlg, 0x0L);
@@ -6553,10 +6899,10 @@ BubblePlot3D::PropertyDlg()
 			}
 		}while (res <0);
 	if(res == 1) {
-		if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
-		if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
-		if(Dlg->GetText(105, TmpTxt)) rZ = new AccRange(TmpTxt);
-		if(Dlg->GetText(151, TmpTxt)) rR = new AccRange(TmpTxt);
+		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
+		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
+		if(Dlg->GetText(105, TmpTxt, TMP_TXT_SIZE)) rZ = new AccRange(TmpTxt);
+		if(Dlg->GetText(151, TmpTxt, TMP_TXT_SIZE)) rR = new AccRange(TmpTxt);
 		if(rX && rY && rZ && rR && (count = rX->CountItems()) 
 			&& (Balls = (Sphere**)calloc(count, sizeof(Sphere*)))) {
 			rX->GetFirst(&cx, &rx);		rY->GetFirst(&cy, &ry);
@@ -6622,7 +6968,7 @@ Func3D::PropertyDlg()
 		{401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
 		{402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
 		{403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
-		{404, 405, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 80, 62, 25, 10},
+		{404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
 		{405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
 		{406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
 		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 45, 130, 100}};
@@ -6640,7 +6986,7 @@ Func3D::PropertyDlg()
 //	if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
 	if(!bNew) Dlg->ShowItem(10, false);
 	Dlg->GetValue(102, &o_x1);		n_x1 = o_x1;
 	Dlg->GetValue(104, &o_x2);		n_x2 = o_x2;
@@ -6648,7 +6994,7 @@ Func3D::PropertyDlg()
 	Dlg->GetValue(108, &o_z1);		n_z1 = o_z1;
 	Dlg->GetValue(109, &o_z2);		n_z2 = o_z2;
 	Dlg->GetValue(110, &o_zstep);	n_zstep = o_zstep;
-	hDlg = CreateDlgWnd("3D Function Plot", 50, 50, 426, 320, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("3D Function Plot", 50, 50, 426, 328, Dlg, 0x0L);
 	if(bNew) Dlg->SetCheck(4, 0L, true);
 	do{
 		LoopDlgWnd();
@@ -6689,10 +7035,9 @@ Func3D::PropertyDlg()
 			Dlg->GetValue(106, &xstep);
 			Dlg->GetValue(108, &z1);		Dlg->GetValue(109, &z2);
 			Dlg->GetValue(110, &zstep);		type = Dlg->GetCheck(305) ? 0 : 1;
-			if(Dlg->GetText(200, TmpTxt)) {
-				if(cmdxy) free(cmdxy);
-				cmdxy = strdup(TmpTxt);		ReshapeFormula(&cmdxy);
-				bRet = Update();
+			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+				if(cmdxy) free(cmdxy);		cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+				ReshapeFormula(&cmdxy);		bRet = Update();
 				}
 			}
 		else {							//edit existing function
@@ -6701,10 +7046,11 @@ Func3D::PropertyDlg()
 			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
 			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
 			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
-			Dlg->GetText(200, TmpTxt);
+			Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
 			if(cmdxy && strcmp(cmdxy, TmpTxt)) {
 				Undo.String(this, &cmdxy, undo_flags);
-				free(cmdxy);	cmdxy = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
+				if(cmdxy) free(cmdxy);		cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+				undo_flags |= UNDO_CONTINUE;
 				}
 //			if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
@@ -6721,7 +7067,7 @@ Func3D::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Fit data to a 3D function
+// Fit a 3D function to data
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool
 FitFunc3D::PropertyDlg()
@@ -6762,7 +7108,7 @@ FitFunc3D::PropertyDlg()
 		{351, 352, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
 		{352, 353, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
 		{353, 354, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
-		{354, 355, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 80, 62, 25, 10},
+		{354, 355, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
 		{355, 356, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
 		{356, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
 		{400, 401, 0, 0x0L, LTEXT, (void*)"range for X data", 10, 30, 60, 8},
@@ -6789,38 +7135,39 @@ FitFunc3D::PropertyDlg()
 	LineDEF newLine;
 	double x, y, z, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2, rad;
 	AccRange *rX, *rY, *rZ;
-	char *o_cmdxy, *o_param;
+	char *o_cmdxy, *o_param, *tmp_char;
 	anyOutput *cdisp = Undo.cdisp;
 	anyResult *ares;
 	Sphere **Balls;
 
 	if(!parent || !data) return false;
 	UseRangeMark(data, 1, text1, text2, text3);
-	if(!(o_cmdxy = strdup(cmdxy))) return false;
-	if(!(o_param = strdup(param))) return false;
+	if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0)))return false;
+	if(!(o_param = (char*)memdup(param, (int)strlen(param)+1, 0)))return false;
 	rX = rY = rZ = 0L;			iter = (double)maxiter;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
 	memcpy(&newLine, &Line, sizeof(LineDEF));
-	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
 	if(!bNew){
 		Dlg->ShowItem(10, false);		Dlg->Activate(401, false);
 		Dlg->Activate(403, false);		Dlg->Activate(405, false);		
 		Dlg->SetCheck(6, 0L, true);
 		Dlg->SetCheck(4, 0L, false);	Dlg->ShowItem(404, false);
 		if(chi2 > 0.0) {
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
+#else
 			sprintf(TmpTxt, "Chi 2 = %g", chi2);
+#endif
 			Dlg->SetText(405,TmpTxt);	Dlg->ShowItem(405, true);
 			}
 		}
-	else {
-		Dlg->ItemCmd(401, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(403, CMD_SET_DATAOBJ, data);
-		Dlg->ItemCmd(405, CMD_SET_DATAOBJ, data);	Dlg->ShowItem(500, false);
-		}
+	else Dlg->ShowItem(500, false);
 	Dlg->GetValue(502, &o_x1);		n_x1 = o_x1;
 	Dlg->GetValue(504, &o_x2);		n_x2 = o_x2;
 	Dlg->GetValue(506, &o_xstep);	n_xstep = o_xstep;
-	hDlg = CreateDlgWnd("Fit Function to Data in 3D Space", 50, 50, 426, 320, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Fit Function to Data in 3D Space", 50, 50, 426, 328, Dlg, 0x0L);
 	if(bNew) Dlg->SetCheck(4, 0L, true);
 	do{
 		LoopDlgWnd();
@@ -6843,11 +7190,13 @@ FitFunc3D::PropertyDlg()
 			break;
 		case 1:
 			if(!bNew){
-				if(Dlg->GetText(102, TmpTxt) && param) {
-					free(param);	param = strdup(TmpTxt);
+				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+					if(param) free(param);	
+					param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 					}
-				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
-					free(cmdxy);	cmdxy = strdup(TmpTxt);
+				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+					if(cmdxy) free(cmdxy);	
+					cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 					}
 				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
 				dirty = true;
@@ -6855,18 +7204,20 @@ FitFunc3D::PropertyDlg()
 				}
 		case 7:								//Start: do nonlinear regression
 			Undo.SetDisp(cdisp);
-			if(!Dlg->GetText(401, text1) || !Dlg->GetText(403, text2) || !Dlg->GetText(405, text3)) {
+			if(!Dlg->GetText(401, text1, 100) || !Dlg->GetText(403, text2, 100) || !Dlg->GetText(405, text3, 100)) {
 				Dlg->SetCheck(4, 0L, true);			bContinue = true;
 				InfoBox("Invalid or missing range");
 				res = -1;
 				}
 			else if(Dlg->GetCheck(5)) {		//  the function tab must be shown
 				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
-				if(Dlg->GetText(102, TmpTxt) && param) {
-					free(param);	param = strdup(TmpTxt);
+				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+					if(param) free(param);	
+					param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 					}
-				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
-					free(cmdxy);	cmdxy = strdup(TmpTxt);
+				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+					if(cmdxy) free(cmdxy);	
+					cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 					}
 				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
 				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
@@ -6882,10 +7233,22 @@ FitFunc3D::PropertyDlg()
 					bContinue = true;	res = -1;
 					break;
 					}
+				i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, param);	i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;z=1;");
+				rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy);	yywarn(0L, true);
+				ares = do_formula(data, TmpTxt);
+				if(tmp_char = yywarn(0L, false)) {
+					ErrorBox(tmp_char);
+					bContinue = true;	res = -1;
+					break;
+					}
 				i = do_fitfunc(data, text1, text2, text3, &param, cmdxy, conv, (int)iter, &chi2);
 				Dlg->SetText(102, param);
 				if(i >1 || res == 7) {
+#ifdef USE_WIN_SECURE
+					sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#else
 					sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#endif
 					InfoBox(TmpTxt);
 					}
 				bContinue = true;
@@ -6924,17 +7287,20 @@ FitFunc3D::PropertyDlg()
 				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
 			x1 = xBounds.fx;		x2 = xBounds.fy;		xstep = (x2-x1)/10.0;
 			z1 = zBounds.fx;		z2 = zBounds.fy;		zstep = (z2-z1)/10.0;
-			if(Dlg->GetText(102, TmpTxt)) {
-				if(param) free(param);	param = strdup(TmpTxt);		ReshapeFormula(&param);
+			if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+				if(param) free(param);	
+				param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 				}
-			if(Dlg->GetText(200, TmpTxt)) {
-				if(cmdxy) free(cmdxy);	cmdxy = strdup(TmpTxt);		ReshapeFormula(&cmdxy);
+			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+				if(cmdxy) free(cmdxy);	
+				cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 				}
+			ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
 			if((bRet = Update()) && gob && nPlots == 1 && (Balls=(Sphere**)calloc(rX->CountItems(), sizeof(Sphere*)))) {
 				rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
 				rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
 				rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
-				rad = defs.GetSize(SIZE_SYMBOL);
+				rad = DefSize(SIZE_SYMBOL);
 				do {
 					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z)) {
 						Balls[ns++] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
@@ -7004,7 +7370,7 @@ GridLine::PropertyDlg()
 
 	if(!parent || !parent->parent) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
-	if(!(Dlg = new DlgRoot(LineDlg)))return false;
+	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
 	if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
 		//no checkboxes
 		}
@@ -7133,7 +7499,7 @@ Tick::PropertyDlg()
 	default:	tick_rot = trig2deg(lsi, lcsi);		break;
 		}
 	old_flags = flags;
-	Dlg = new DlgRoot(TickDlg);
+	Dlg = new DlgRoot(TickDlg, data);
 	Dlg->SetCheck(301 + (type & 0x07), 0L, true);
 	if(flags & AXIS_ANGULAR) {
 		Dlg->SetText(105, "outside");		Dlg->SetText(106, "inside");
@@ -7162,11 +7528,9 @@ Tick::PropertyDlg()
 			}
 		}
 	if(label) {
-		label->Command(CMD_GETTEXT, &TmpTxt, 0L);
-		if(TmpTxt[0]) {
-			old_label = strdup(TmpTxt);
+		if(label->Command(CMD_GETTEXT, &TmpTxt, 0L) && TmpTxt[0] && 
+			(old_label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0)))
 			Dlg->SetText(203, old_label);
-			}
 		if(label->Id != GO_LABEL) Dlg->Activate(203, false);
 		}
 	switch(flags &0x03) {
@@ -7212,7 +7576,7 @@ Tick::PropertyDlg()
 		undo_flags = CheckNewFloat(&value, old_value, new_value, parent, undo_flags);
 		if(label && label->Id == GO_LABEL) {
 			td = ((Label*)label)->GetTextDef();
-			if(!Dlg->GetText(203, TmpTxt)) TmpTxt[0] = 0;
+			if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
 			if(td->text && strcmp(td->text, TmpTxt)) {
 				Undo.String(this, &td->text, undo_flags);
 				undo_flags |= UNDO_CONTINUE;
@@ -7264,9 +7628,7 @@ Axis::ssTicks()
 
 	if(!data) return false;
 	n = n1 = n2 = n3 = 0;			rT = rL = rMT = 0L;
-	if(!(Dlg = new DlgRoot(TickDlg)))return false;
-	Dlg->ItemCmd(4, CMD_SET_DATAOBJ, data);		Dlg->ItemCmd(6, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(8, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(TickDlg, data)))return false;
 	hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x0L);
 	Dlg->Activate(4, true);
 	do{
@@ -7282,8 +7644,8 @@ Axis::ssTicks()
 		case 1:
 			if(rT) delete rT;		if(rL) delete rL;		if(rMT) delete rMT;
 			n = n1 = n2 = n3 = 0;	rT = rL = rMT = 0L;
-			if(Dlg->GetText(4,TmpTxt) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
-				if(Dlg->GetText(6,TmpTxt) && (rL = new AccRange(TmpTxt)) && 
+			if(Dlg->GetText(4,TmpTxt, TMP_TXT_SIZE) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
+				if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE) && (rL = new AccRange(TmpTxt)) && 
 					(n2 = rL->CountItems()) && n1 != n2){
 					ErrorBox("Ranges for tick values\nand tick labels must"
 						" have\nthe same size");
@@ -7291,7 +7653,7 @@ Axis::ssTicks()
 					break;
 					}
 				}
-			if(Dlg->GetText(8,TmpTxt) && (rMT=new AccRange(TmpTxt)) && (n3=rMT->CountItems())){
+			if(Dlg->GetText(8,TmpTxt,TMP_TXT_SIZE) && (rMT=new AccRange(TmpTxt)) && (n3=rMT->CountItems())){
 				//minor ticks are valid
 				}
 			if(!(n = n1 + n3)) {
@@ -7304,9 +7666,12 @@ Axis::ssTicks()
 		if(n1) {
 			if(ssMATval) free(ssMATval);	if(ssMATlbl) free(ssMATlbl);
 			if(ssMITval) free(ssMITval);	ssMATval = ssMATlbl = ssMITval = 0L;
-			if(Dlg->GetText(4, TmpTxt))ssMATval = strdup(TmpTxt);
-			if(Dlg->GetText(6, TmpTxt))ssMATlbl = strdup(TmpTxt);
-			if(Dlg->GetText(8, TmpTxt))ssMITval = strdup(TmpTxt);
+			if(Dlg->GetText(4, TmpTxt, TMP_TXT_SIZE)) 
+				ssMATval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+			if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE))
+				ssMATlbl = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+			if(Dlg->GetText(8, TmpTxt, TMP_TXT_SIZE))
+				ssMITval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 			UpdateTicks();
 			}
 		bRet = true;
@@ -7366,7 +7731,7 @@ Axis::PropertyDlg()
 		{122, 123, 0, 0x0L, EDVAL1, &sizAxLine, 37, 128, 25, 10},
 		{123, 124, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 63, 128, 10, 8},
 		{124, 125, 0, 0x0L, RTEXT, (void*)"color", 82, 128, 25, 8},
-		{125, 130, 0, OWNDIALOG, COLBUTTON, (void *)colAxis, 109, 128, 25, 10},
+		{125, 130, 0, OWNDIALOG, COLBUTT, (void *)&colAxis, 109, 128, 25, 10},
 		{130, 0, 131, ISPARENT | CHECKED, GROUPBOX, (void*)" axis label ", 10, 149, 138, 20},
 		{131, 0, 0, 0x0L, EDTEXT, (void*)"abc", 15, 154, 128, 10},
 		{180, 0, 181, HIDDEN | ISPARENT | CHECKED, GROUPBOX, (void*)" placement ", 10, 72, 138, 45},
@@ -7445,20 +7810,20 @@ Axis::PropertyDlg()
 		if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
 			!(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
 			return false;
-		names[j=0] = strdup("[unchanged]");
+		if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
 		for(i = 0, j = 1; i < res; i++) {
 			if(scp[i] && scp[i]->name){
-				names[j] = strdup(scp[i]->name);
+				names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
 				somePlots[j++] = scp[i];
 				}
 			}
 		}
 	else {
-		names = (char**)calloc(2, sizeof(char*));
-		names[0] = strdup("n.a.");
+		names = (char**)calloc(2, sizeof(char*));	names[0] = (char*)malloc(10*sizeof(char));
+		rlp_strcpy(names[0], 10, "n.a.");
 		}
 	OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
-	if(!(Dlg = new DlgRoot(AxisDlg)))return false;
+	if(!(Dlg = new DlgRoot(AxisDlg, data)))return false;
 	if(names && somePlots) Dlg->ShowItem(8, true);		//show tab
 	if(axis->breaks && axis->nBreaks) {
 		if(!(brks = (lfPOINT*)calloc(axis->nBreaks+2, sizeof(lfPOINT)))) return false;
@@ -7533,7 +7898,7 @@ Axis::PropertyDlg()
 		TmpTxt[0] = 0;
 		axisLabel->Command(CMD_GETTEXT, TmpTxt, 0L);
 		Dlg->SetText(131,TmpTxt);
-		old_Label = strdup(TmpTxt);
+		old_Label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 		if(axisLabel->Id == GO_MLABEL) Dlg->Activate(131, false);
 		}
 	else Dlg->SetText(131, 0L);
@@ -7561,7 +7926,8 @@ Axis::PropertyDlg()
 	Dlg->GetValue(182, &old_a.Center.fx);	Dlg->GetValue(185, &old_a.Center.fy);
 	Dlg->GetValue(188, &old_a.Radius);
 	memcpy(&new_a, &old_a, sizeof(AxisDEF));
-	sprintf(TmpTxt, "%sxis properties", type_txt);
+	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, type_txt);
+	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "xis properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 436, 384, Dlg, 0x0L);
 	switch(axis->flags & 0x70) {
 		case AXIS_LEFT: 
@@ -7576,7 +7942,11 @@ Axis::PropertyDlg()
 	do{
 		if(upd_brk) {
 			Dlg->ShowItem(453, cbrk > 0);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "break # %d/%d", cbrk+1, nbrk+1);
+#else
 			sprintf(TmpTxt,"break # %d/%d", cbrk+1, nbrk+1);
+#endif
 			Dlg->SetText(451, TmpTxt);
 			upd_brk = false;
 			}
@@ -7802,16 +8172,17 @@ Axis::PropertyDlg()
 			}
 		if(Dlg->GetValue(122, &tmp)) 
 			undo_flags = CheckNewFloat(&sizAxLine, sizAxLine, tmp, this, undo_flags);
-		if(Dlg->GetText(131, TmpTxt) && TmpTxt[0]) {
+		if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
 			if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
 				lb_def = ((Label*)axisLabel)->GetTextDef();
 				Undo.String(axisLabel, &lb_def->text, undo_flags);
 				if(lb_def->text) free(lb_def->text);
-				lb_def->text = strdup(TmpTxt);		undo_flags |= UNDO_CONTINUE;
+				lb_def->text = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+				undo_flags |= UNDO_CONTINUE;
 				}
 			else if(!axisLabel) {
 				label_def.ColTxt = colAxis;				label_def.ColBg = 0x00ffffffL;
-				label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2;
+				label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2;
 				label_def.RotBL = fabs(si)>0.80 ? 90.0 : 0.0;
 				label_def.RotCHAR = 0.0f;				label_def.iSize = 0;
 				label_def.Align = TXA_VCENTER | TXA_HCENTER;
@@ -7914,7 +8285,7 @@ Graph::AddPlot(int family)
 		InfoBox("Don\'t know how to\nadd a plot to the\ncurrent graph.");
 		return false;
 		}
-	Dlg = new DlgRoot(GraphDlg);
+	Dlg = new DlgRoot(GraphDlg, data);
 	hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 240, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -7938,7 +8309,7 @@ Graph::AddPlot(int family)
 		else if(Dlg->GetCheck(523)) p = new PlotScatt(this, data, 0x04);
 		else if(Dlg->GetCheck(526)) p = new Regression(this, data);
 		else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
-		else if(Dlg->GetCheck(529)) p = new Function(this, data);
+		else if(Dlg->GetCheck(529)) p = new Function(this, data, "Function");
 		else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
 		else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
 		else if(Dlg->GetCheck(532)) p = new xyStat(this, data);
@@ -8067,7 +8438,7 @@ Graph::PropertyDlg()
 	ODtickstyle = tickstyle;
 	AxisTempl = 0;
 	if(!parent) return false;
-	Dlg = new DlgRoot(GraphDlg);
+	Dlg = new DlgRoot(GraphDlg, data);
 	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
 	if(parent->Id != GO_PAGE) {
 		Dlg->Activate(202, false);	Dlg->Activate(204, false);
@@ -8193,7 +8564,7 @@ Graph::PropertyDlg()
 				else if(Dlg->GetCheck(526)) p = new Regression(this, data);
 				else if(Dlg->GetCheck(527)) p = new PolarPlot(this, data);
 				else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
-				else if(Dlg->GetCheck(529)) p = new Function(this, data);
+				else if(Dlg->GetCheck(529)) p = new Function(this, data, "Function");
 				else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
 				else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
 				else if(Dlg->GetCheck(532)) p = new xyStat(this, data);
@@ -8255,15 +8626,15 @@ Graph::Configure()
 		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
 		{100, 101, 0, 0x0L, LTEXT, (void*)"bounding rectangle", 20, 30, 60, 8},
 		{101, 102, 0, 0x0L, RTEXT, (void*)"fill color", 15, 42, 58, 8},
-		{102, 103, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColGR, 74, 42, 25, 10},
+		{102, 103, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColGR, 74, 42, 25, 10},
 		{103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 15, 54, 58, 8},
-		{104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColGRL, 74, 54, 25, 10},
+		{104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColGRL, 74, 54, 25, 10},
 		{105, 106, 0, 0x0L, LTEXT, (void*)"plotting rectangle", 20, 68, 60, 8},
 		{106, 107, 0, 0x0L, RTEXT, (void*)"fill color", 15, 80, 58, 8},
-		{107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColDR, 74, 80, 25, 10},
+		{107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColDR, 74, 80, 25, 10},
 		{108, 109, 0, 0x0L, LTEXT, (void*)"axes, ticks, and axis labels", 20, 94, 60, 8},
 		{109, 110, 0, 0x0L, RTEXT, (void*)"axis color", 15, 106, 58, 8},
-		{110, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColAX, 74, 106, 25, 10},
+		{110, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColAX, 74, 106, 25, 10},
 		{200, 201, 0, 0x0L, LTEXT, (void*)"bounding rectangle (relative to page)", 10, 35, 60, 8},
 		{201, 202, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 47, 58, 8},
 		{202, 203, 0, 0x0L, EDVAL1, &GRect.Xmin, 64, 47, 30, 10},
@@ -8298,13 +8669,14 @@ Graph::Configure()
 	bool bRet = false, bContinue = false;
 	fRECT o_gr, n_gr, o_dr, n_dr;
 
-	if(!(Dlg = new DlgRoot(GraphDlg)))return false;
+	if(!(Dlg = new DlgRoot(GraphDlg, data)))return false;
 	Dlg->GetValue(202, &o_gr.Xmin);			Dlg->GetValue(204, &o_gr.Ymin);
 	Dlg->GetValue(207, &o_gr.Xmax);			Dlg->GetValue(209, &o_gr.Ymax);
 	Dlg->GetValue(213, &o_dr.Xmin);			Dlg->GetValue(215, &o_dr.Ymin);
 	Dlg->GetValue(218, &o_dr.Xmax);			Dlg->GetValue(220, &o_dr.Ymax);
 	if(parent && parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
-	sprintf(TmpTxt, "%s properties", name ? name : "Graph");
+	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name ? name : (char*)"Graph");
+	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, (char*)" properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 450, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();			res = Dlg->GetResult();
@@ -8433,7 +8805,7 @@ static char *AddAxisTmpl =
 		"205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
 		"206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
 		"207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
-		"208,210,,EXRADIO,, ODBUTTON,17,95,67,25,25\n"
+		"208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
 		"210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
 		"220,221,,,RTEXT,-4,10,105,15,8\n"
 		"221,222,,,EDVAL1,19,27,105,35,10\n"
@@ -8454,7 +8826,7 @@ Graph::AddAxis()
 	TabSHEET tab2 = {25, 52, 10, "Style"};
 	TabSHEET tab3 = {52, 78, 10, "Plots"};
 	AxisDEF axis;
-	double sizAxLine = defs.GetSize(SIZE_AXIS_LINE);
+	double sizAxLine = DefSize(SIZE_AXIS_LINE);
 	DWORD colAxis = ColAX;
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
 		(void*)"axis from", (void*)&y_axis.min, (void*)"to", (void*)&y_axis.max, (void*)" line ", (void*)"width",
@@ -8479,10 +8851,10 @@ Graph::AddAxis()
 	if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
 	if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
 	if(!Axes) Axes = (Axis**)calloc(2, sizeof(Axis*));
-	names[j=0] = strdup("[none]");
+	if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
 	for(i = 0, j = 1; i < nscp; i++) {
 		if(Sc_Plots[i] && Sc_Plots[i]->name){
-			names[j] = strdup(Sc_Plots[i]->name);
+			names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
 			somePlots[j++] = Sc_Plots[i];
 			}
 		}
@@ -8493,11 +8865,11 @@ Graph::AddAxis()
 	axis.min = y_axis.min;		axis.max = y_axis.max;
 	hy1 = hy2 = (DRect.Ymax + DRect.Ymin)/2.0;
 	hx1 = DRect.Xmin;			hx2 = DRect.Xmax;
-	if(!(Dlg = new DlgRoot(NewAxisDlg)))return false;
+	if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
 	if(type != 1 || !nscp){		//must be standard graph to link to plot
 		Dlg->ShowItem(6, false);
 		}
-	hDlg = CreateDlgWnd("New axis properties", 50, 50, 400, 314, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("New axis properties", 50, 50, 400, 318, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -8509,31 +8881,25 @@ Graph::AddAxis()
 		case 201:	case 202:	case 203:	case 204:	//axis templates
 		case 205:	case 206:	case 207:	case 208:
 			if(currTempl > 204) {
-				Dlg->GetValue(221, &hx1);			Dlg->GetValue(223, &hx2);
-				Dlg->GetValue(226, &hy1);			Dlg->GetValue(228, &hy2);
+				Dlg->GetValue(221, &hx1);				Dlg->GetValue(223, &hx2);
+				Dlg->GetValue(226, &hy1);				Dlg->GetValue(228, &hy2);
 				}
 			else {
-				Dlg->GetValue(221, &vx1);			Dlg->GetValue(223, &vx2);
-				Dlg->GetValue(226, &vy1);			Dlg->GetValue(228, &vy2);
+				Dlg->GetValue(221, &vx1);				Dlg->GetValue(223, &vx2);
+				Dlg->GetValue(226, &vy1);				Dlg->GetValue(228, &vy2);
 				}
 			if(res > 204) {
-				WriteFloatToBuff(TmpTxt, hx1);		Dlg->SetText(221, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, hx2);		Dlg->SetText(223, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, hy1);		Dlg->SetText(226, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, hy2);		Dlg->SetText(228, TmpTxt+1);
+				Dlg->SetValue(221, hx1);				Dlg->SetValue(223, hx2);
+				Dlg->SetValue(226, hy1);				Dlg->SetValue(228, hy2);
 				if(! bAxis) {
-					WriteFloatToBuff(TmpTxt, x_axis.min);	Dlg->SetText(101, TmpTxt+1);
-					WriteFloatToBuff(TmpTxt, x_axis.max);	Dlg->SetText(103, TmpTxt+1);
+					Dlg->SetValue(101, x_axis.min);		Dlg->SetValue(103, x_axis.max);
 					}
 				}
 			else {
-				WriteFloatToBuff(TmpTxt, vx1);		Dlg->SetText(221, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, vx2);		Dlg->SetText(223, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, vy1);		Dlg->SetText(226, TmpTxt+1);
-				WriteFloatToBuff(TmpTxt, vy2);		Dlg->SetText(228, TmpTxt+1);
+				Dlg->SetValue(221, vx1);				Dlg->SetValue(223, vx2);
+				Dlg->SetValue(226, vy1);				Dlg->SetValue(228, vy2);
 				if(! bAxis) {
-					WriteFloatToBuff(TmpTxt, y_axis.min);	Dlg->SetText(101, TmpTxt+1);
-					WriteFloatToBuff(TmpTxt, y_axis.max);	Dlg->SetText(103, TmpTxt+1);
+					Dlg->SetValue(101, y_axis.min);		Dlg->SetValue(103, y_axis.max);
 					}
 				}
 			currTempl = res;
@@ -8551,15 +8917,15 @@ Graph::AddAxis()
 		Dlg->GetValue(101, &axis.min);				Dlg->GetValue(103, &axis.max);
 		axis.Start = axis.min;				axis.Center.fx = axis.Center.fy = 0.0;
 		axis.nBreaks = 0;			axis.breaks = 0L;		axis.Radius = 0.0;	
-		tlb_dist = NiceValue(defs.GetSize(SIZE_AXIS_TICKS));
+		tlb_dist = NiceValue(DefSize(SIZE_AXIS_TICKS));
 		tlb_dx = tlb_dy = 0.0;
 		tlbdef.ColTxt = colAxis;				tlbdef.ColBg = 0x00ffffffL;
-		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;	tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
+		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
 		tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
 		tlbdef.Style = TXS_NORMAL;				tlbdef.Mode = TXM_TRANSPARENT;
 		tlbdef.Font = FONT_HELVETICA;			tlbdef.text = 0L;
 		label_def.ColTxt = colAxis;				label_def.ColBg = 0x00ffffffL;
-		label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2f;	label_def.RotBL = 0.0f;
+		label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2f;	label_def.RotBL = 0.0f;
 		label_def.RotCHAR = 0.0f;								label_def.iSize = 0;
 		label_def.Align = TXA_VTOP | TXA_HCENTER;		label_def.Mode = TXM_TRANSPARENT;
 		label_def.Style = TXS_NORMAL;	label_def.Font = FONT_HELVETICA;
@@ -8609,7 +8975,7 @@ Graph::AddAxis()
 			the_new->SetColor(COL_AXIS, colAxis);
 			the_new->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
 			the_new->SetSize(SIZE_LB_XDIST, lb_x);		the_new->SetSize(SIZE_LB_YDIST, lb_y); 
-			if(Dlg->GetText(131, TmpTxt)) label_def.text = TmpTxt;
+			if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) label_def.text = TmpTxt;
 			else label_def.text = 0L;
 			if(label = new Label(Axes[0], data, (axis.loc[0].fx + axis.loc[1].fx)/2.0,
 				(axis.loc[0].fy + axis.loc[1].fy)/2.0, &label_def, 
@@ -8662,12 +9028,14 @@ Page::Configure()
 		{100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_paperdef, 15, 30, 110, 140}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res;
+	int res, cb;
 	bool bRet = false, bContinue = false;
 
 	FindPaper(GRect.Xmax - GRect.Xmin, GRect.Ymax -GRect.Ymin, .0001);
-	if(!(Dlg = new DlgRoot(PageDlg)))return false;
-	sprintf(TmpTxt, "%s properties", name ? name : "Page");
+	if(!(Dlg = new DlgRoot(PageDlg, data)))return false;
+	if(name)cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name);
+	else cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Page");
+	rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, " properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 380, 300, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
@@ -8749,7 +9117,7 @@ Default::PropertyDlg()
 		{422, 0, 0, LASTOBJ, RADIO1, (void*)Units[2].display, 75, 91, 20, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, res, tmpUnits = cUnits;
+	int i, cb, res, tmpUnits = cUnits;
 	bool bRet = false, bContinue = false;
 	double dt;
 	LineDEF LineDef;
@@ -8758,13 +9126,18 @@ Default::PropertyDlg()
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)GetLine(), 0);
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)GetOutLine(), 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)GetFill(), 0);
-	sprintf(dt_info, "today is %s", ctime(&ti));
-	dt_info[33] = 0;
+	cb = rlp_strcpy(dt_info, 20, "today is ");
+#ifdef USE_WIN_SECURE
+	ctime_s(dt_info+cb, 50-cb, &ti);
+#else
+	rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
+#endif
+	dt_info[cb+24] = 0;
 	date_value(dt_info+13, "x z H:M:S Y", &dt);
-	strcpy(date_info, value_date(dt, defs.fmt_date));
-	strcpy(datetime_info, value_date(dt, defs.fmt_datetime));
-	strcpy(time_info, value_date(dt, defs.fmt_time));
-	Dlg = new DlgRoot(DefsDlg);
+	rlp_strcpy(date_info, 50, value_date(dt, defs.fmt_date));
+	rlp_strcpy(datetime_info, 50, value_date(dt, defs.fmt_datetime));
+	rlp_strcpy(time_info, 50, value_date(dt, defs.fmt_time));
+	Dlg = new DlgRoot(DefsDlg, 0L);
 	switch(dUnits) {
 	case 1:		Dlg->SetCheck(421, 0L, true);	break;
 	case 2:		Dlg->SetCheck(422, 0L, true);	break;
@@ -8783,17 +9156,21 @@ Default::PropertyDlg()
 		case 0:
 			if(bContinue) res = -1;
 			break;
-		case 362:			//update date/time display
-			ti = time(0L);
-			sprintf(dt_info, "today is %s", ctime(&ti));
-			dt_info[33] = 0;										Dlg->SetText(350, dt_info);
+		case 362:				//update date/time display
+			ti = time(0L);		cb = rlp_strcpy(dt_info, 20, "today is ");
+#ifdef USE_WIN_SECURE
+			ctime_s(dt_info+cb, 50-cb, &ti);
+#else
+			rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
+#endif
+			dt_info[cb+24] = 0;												Dlg->SetText(350, dt_info);
 			date_value(dt_info+13, "x z H:M:S Y", &dt);
-			if(!(Dlg->GetText(352, date_info))) strcpy(date_info, defs.fmt_date);
-			strcpy(date_info, value_date(dt, date_info));			Dlg->SetText(353, date_info);
-			if(!(Dlg->GetText(355, datetime_info))) strcpy(datetime_info, defs.fmt_datetime);
-			strcpy(datetime_info, value_date(dt, datetime_info));	Dlg->SetText(356, datetime_info);
-			if(!(Dlg->GetText(358, time_info))) strcpy(time_info, defs.fmt_time);
-			strcpy(time_info, value_date(dt, time_info));			Dlg->SetText(359, time_info);
+			if(!(Dlg->GetText(352, date_info, 50))) rlp_strcpy(date_info, 50, defs.fmt_date);
+			rlp_strcpy(date_info, 50, value_date(dt, date_info));			Dlg->SetText(353, date_info);
+			if(!(Dlg->GetText(355, datetime_info, 50))) rlp_strcpy(datetime_info, 50, defs.fmt_datetime);
+			rlp_strcpy(datetime_info, 50, value_date(dt, datetime_info));	Dlg->SetText(356, datetime_info);
+			if(!(Dlg->GetText(358, time_info, 50))) rlp_strcpy(time_info, 50, defs.fmt_time);
+			rlp_strcpy(time_info, 50, value_date(dt, time_info));			Dlg->SetText(359, time_info);
 			bContinue = false;		res = -1;
 			break;
 		case 361:			//call browser
@@ -8812,8 +9189,8 @@ Default::PropertyDlg()
 			}
 		}while (res < 0);
 	if(res == 1) {
-		if(Dlg->GetText(402, TmpTxt))	DecPoint[0] = TmpTxt[0];
-		if(Dlg->GetText(404, TmpTxt))	ColSep[0] = TmpTxt[0];
+		if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE))	DecPoint[0] = TmpTxt[0];
+		if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE))	ColSep[0] = TmpTxt[0];
 		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
 		SetLine(tmpUnits, &LineDef, 0);
 		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
@@ -8821,17 +9198,17 @@ Default::PropertyDlg()
 		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&FillDef, 0);
 		SetFill(tmpUnits, &FillDef);
 		Dlg->GetInt(301, &dlgtxtheight);
-		if(Dlg->GetText(352, date_info) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
-			if(defs.fmt_date) free(defs.fmt_date);
-			defs.fmt_date = strdup(date_info);
+		if(Dlg->GetText(352, date_info, 50) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
+			if(defs.fmt_date = (char*)realloc(defs.fmt_date, (cb = (int)strlen(date_info) +2)))
+				rlp_strcpy(defs.fmt_date, cb, date_info);
 			}
-		if(Dlg->GetText(355, datetime_info) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
-			if(defs.fmt_datetime) free(defs.fmt_datetime);
-			defs.fmt_datetime = strdup(datetime_info);
+		if(Dlg->GetText(355, datetime_info, 50) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
+			if(defs.fmt_datetime = (char*)realloc(defs.fmt_datetime, (cb = (int)strlen(datetime_info) +2)))
+				rlp_strcpy(defs.fmt_datetime, cb, datetime_info);
 			}
-		if(Dlg->GetText(358, time_info) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
-			if(defs.fmt_time) free(defs.fmt_time);
-			defs.fmt_time = strdup(time_info);
+		if(Dlg->GetText(358, time_info, 50) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
+			if(defs.fmt_time = (char*)realloc(defs.fmt_time, (cb = (int)strlen(time_info) +2)))
+				rlp_strcpy(defs.fmt_time, cb, time_info);
 			}
 		bRet = true;
 		}
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index c3eb457..8623c1c 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -1,183 +1,195 @@
-//QT_Spec.cpp, Copyright (c) 2001-2006 R.Lackner
-//
-//    This file is part of RLPlot.
-//
-//    RLPlot 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.
-//
-//    RLPlot 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 RLPlot; if not, write to the Free Software
-//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-//
-#include <qmessagebox.h>
-#include <qpixmap.h>
-#include <qapplication.h>
-#include <qnamespace.h>
-#include <qfiledialog.h>
-#include <qpaintdevicemetrics.h>
-#include <qimage.h>
-#include <qcursor.h>
-#include <qcstring.h>
-#include <qclipboard.h>
-#include <qbuffer.h>
+//QT_Spec.cpp, Copyright (c) 2001-2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot 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.
+//
+//    RLPlot 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 RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+#include <qmessagebox.h>
+#include <qpixmap.h>
+#include <qapplication.h>
+#include <qnamespace.h>
+#include <qfiledialog.h>
+#include <qpaintdevicemetrics.h>
+#include <qimage.h>
+#include <qcursor.h>
+#include <qcstring.h>
+#include <qclipboard.h>
+#include <qbuffer.h>
 #include <qbitmap.h>
-#include <qtextstream.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
+#include <qtextstream.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
 #include "QT_Spec.h"
 #include "menu.h"
 
-extern tag_Units Units[];
-extern GraphObj *CurrGO;			//Selected Graphic Objects
-extern Graph *CurrGraph;
-extern char *WWWbrowser;
-extern char *LoadFile;				//command line argument
-extern char TmpTxt[];
-extern Default defs;
+extern tag_Units Units[];
+extern GraphObj *CurrGO;			//Selected Graphic Objects
+extern Graph *CurrGraph;
+extern char *WWWbrowser;
+extern char *LoadFile;				//command line argument
+extern char TmpTxt[];
+extern Default defs;
 extern UndoObj Undo;
-
-QApplication *QAppl;
-QWidget *MainWidget =0L;
-POINT CurrWidgetPos = {0,0};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Exute a file open dialog for the different situations
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char UserFileName[600];
-// Get a new file name to store data in
-char *SaveDataAsName(char *oldname)
+
+QApplication *QAppl;
+QWidget *MainWidget =0L;
+POINT CurrWidgetPos = {0,0};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Exute a file open dialog for the different situations
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char UserFileName[600];
+// Get a new file name to store data in
+char *SaveDataAsName(char *oldname)
 {
 	QFileDialog qf(0,0,true);
 	QString filters("RLPlot workbook (*.rlw);;data files (*.csv);;"
 		"tab separated (*.tsv);;XML (*.xml)");
+	int i, cb;
+	char *ext;
 
 	qf.setFilters(filters);				qf.setDir(defs.currPath);
 	qf.setSelection(oldname);			qf.setMode(QFileDialog::AnyFile);
 	if(qf.exec() == QDialog::Accepted) {
-//		InfoBox((char*)qf.selectedFilter().ascii());
-//		InfoBox((char*)qf.selectedFile().ascii());
 		if(!qf.selectedFile().isEmpty()) {
-			strcpy(UserFileName, (char*)qf.selectedFile().ascii());
+			cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFile().ascii());
+			if(cb < 4 || UserFileName[cb-4] != '.'){
+				ext = (char*)qf.selectedFilter().ascii();
+				for(i = 0; ext[i] && ext[i] != '*'; i++);
+				rlp_strcpy(UserFileName+cb, 5, ext+i+1);
+				}
 			defs.FileHistory(UserFileName);
 			return UserFileName;
 			}
 		}
 	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get a new file name to store graph
-char *SaveGraphAsName(char *oldname)
-{
-	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
-		"RLPlot files (*.rlp)", QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		defs.FileHistory(UserFileName);
-		return UserFileName;
-		}
-	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get file name to read graph
-char *OpenGraphName(char *oldname)
-{
-	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
-		"RLPlot files (*.rlp)", QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		defs.FileHistory(UserFileName);
-		return UserFileName;
-		}
-	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get a file name to load data
-char *OpenDataName(char *oldname)
-{
-	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a new file name to store graph
+char *SaveGraphAsName(char *oldname)
+{
+	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
+		"RLPlot files (*.rlp)", QAppl->focusWidget());
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get file name to read graph
+char *OpenGraphName(char *oldname)
+{
+	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+		"RLPlot files (*.rlp)", QAppl->focusWidget());
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to load data
+char *OpenDataName(char *oldname)
+{
+	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
 		"RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n"
-		"RLPlot files (*.rlp)\nall files (*.*)", QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		defs.FileHistory(UserFileName);
-		return UserFileName;
-		}
-	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get a file name to export graph
-void OpenExportName(GraphObj *g, char *oldname)
-{
-	int i;
-	PrintQT *out=0L;
-
-	if (!g) return;
-	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
-		"Scalable Vector Graphics (*.svg)\nEncapsulated Post Script (*.eps)\n"
-		"MSWindows MetaFile (*.wmf)\nTag Image File Format(*.tif *.tiff)", 
-		QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		i = strlen(UserFileName);
-		g->Command(CMD_BUSY, 0L, 0L);
-		if(0==strcasecmp(".svg", UserFileName+i-4)) {
-			DoExportSvg(g, UserFileName, 0L);
-			}
-		else if(0==strcasecmp(".wmf", UserFileName+i-4)) {
-			DoExportWmf(g, UserFileName, 600.0f, 0L);
-			}
-		else if(0==strcasecmp(".eps", UserFileName+i-4)) {
-			DoExportEps(g, UserFileName, 0L);
-			}
-		else if(0==strcasecmp(".tif", UserFileName+i-4)) {
-			DoExportTif(g, UserFileName, 0L);
-			}
-		else if(0==strcasecmp(".tiff", UserFileName+i-5)) {
-			DoExportTif(g, UserFileName, 0L);
-			}
-		else ErrorBox("Unknown file extension or format");
-		g->Command(CMD_MOUSECURSOR, 0L, 0L);
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Common alert boxes
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void InfoBox(char *Msg)
+		"RLPlot files (*.rlp)\nall files (*.*)", QAppl->focusWidget());
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to export graph
+void OpenExportName(GraphObj *g, char *oldname)
+{
+	int i;
+	PrintQT *out=0L;
+
+	if (!g) return;
+	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
+		"Scalable Vector Graphics (*.svg)\nEncapsulated Post Script (*.eps)\n"
+		"MSWindows MetaFile (*.wmf)\nTag Image File Format(*.tif *.tiff)", 
+		QAppl->focusWidget());
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		i = strlen(UserFileName);
+		g->Command(CMD_BUSY, 0L, 0L);
+		if(0==strcasecmp(".svg", UserFileName+i-4)) {
+			DoExportSvg(g, UserFileName, 0L);
+			}
+		else if(0==strcasecmp(".wmf", UserFileName+i-4)) {
+			DoExportWmf(g, UserFileName, 600.0f, 0L);
+			}
+		else if(0==strcasecmp(".eps", UserFileName+i-4)) {
+			DoExportEps(g, UserFileName, 0L);
+			}
+		else if(0==strcasecmp(".tif", UserFileName+i-4)) {
+			DoExportTif(g, UserFileName, 0L);
+			}
+		else if(0==strcasecmp(".tiff", UserFileName+i-5)) {
+			DoExportTif(g, UserFileName, 0L);
+			}
+		else ErrorBox("Unknown file extension or format");
+		g->Command(CMD_MOUSECURSOR, 0L, 0L);
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common alert boxes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char the_message[500];
+void InfoBox(char *Msg)
 {
 	QMessageBox::information(QAppl->focusWidget(), "Info", Msg);
 }
-
-void ErrorBox(char *Msg)
-{
-	QMessageBox::critical(QAppl->focusWidget(), "ERROR", Msg);
-}
-
-bool YesNoBox(char *Msg)
-{
-	if(QMessageBox::information(QAppl->focusWidget(), "RLPlot", Msg,
-		"&Yes", "&No", 0L, 0, -1)) return false;
-	return true;
-}
-
+
+void ErrorBox(char *Msg)
+{
+	QMessageBox::critical(QAppl->focusWidget(), "ERROR", Msg);
+}
+
+bool YesNoBox(char *Msg)
+{
+	int cb;
+
+	cb = rlp_strcpy(the_message, 450, Msg);
+	rlp_strcpy(the_message+cb, 500-cb, "\n");
+	if(QMessageBox::information(QAppl->focusWidget(), "RLPlot", the_message,
+		"&Yes", "&No", 0L, 0, -1)) return false;
+	return true;
+}
+
 int YesNoCancelBox(char *Msg)
 {
-	int res;
+	int res, cb;
 
-	res = QMessageBox::information(QAppl->focusWidget(), "RLPlot", Msg,
+	cb = rlp_strcpy(the_message, 450, Msg);
+	rlp_strcpy(the_message+cb, 500-cb, "\n");
+	res = QMessageBox::information(QAppl->focusWidget(), "RLPlot", the_message,
 		"&Yes", "&No", "&Cancel", 0, -1);
 	switch(res) {
 	case 0:		return 1;
@@ -186,148 +198,148 @@ int YesNoCancelBox(char *Msg)
 		}
 	return 0;
 }
-
-void Qt_Box()
-{
-	QMessageBox::aboutQt(QAppl->focusWidget(), "RLPlot uses Qt");
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Display blinking text cursor
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-anyOutput *oTxtCur = 0L;
-RECT rTxtCur, rCopyMark;
-bool bTxtCur = false;
-DWORD coTxtCur = 0x0L;
-TxtCurBlink *cTxtCur = 0L;
-POINT ptTxtCurLine[2];
-
-void HideTextCursor()
-{
-	if(oTxtCur) {
-		bTxtCur = false;
-		oTxtCur->UpdateRect(&rTxtCur, false);
-		}
-	oTxtCur = 0L;
-}
-
-void HideTextCursorObj(anyOutput *out)
-{
-	if(oTxtCur && oTxtCur == out) HideTextCursor();
-}
-
-void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
-{
-	coTxtCur = color;
-	HideTextCursor();
-	oTxtCur = out;
-	memcpy(&rTxtCur, disp, sizeof(RECT));
-	ptTxtCurLine[0].x = rTxtCur.left;	ptTxtCurLine[0].y = rTxtCur.top;
-	ptTxtCurLine[1].x = rTxtCur.right;	ptTxtCurLine[1].y = rTxtCur.bottom;
-	rTxtCur.bottom++;		rTxtCur.right++;
-	bTxtCur = true;
-	if(cTxtCur) cTxtCur->Show();
-}
-
-void InitTextCursor(bool init)
-{
-	if(init && !cTxtCur) cTxtCur = new TxtCurBlink();
-	else if(!init && cTxtCur) {
-		delete cTxtCur;
-		cTxtCur = 0L;
-		}
-}
-
-void HideCopyMark()
-{
-	if(cTxtCur && cTxtCur->bmCopyMark && cTxtCur->oCopyMark) {
-		cTxtCur->oCopyMark->UpdateRect(&rCopyMark, false);
-		delete cTxtCur->bmCopyMark;
-		}
-	cTxtCur->bmCopyMark = 0L;	cTxtCur->oCopyMark = 0L;
-}
-
-void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
-{
-	int i;
-
-	if(!out || !mrk || !nRec || !cTxtCur) return;
-	cTxtCur->oCopyMark = out;
-	rCopyMark.left = mrk[0].left;	rCopyMark.right = mrk[0].right;
-	rCopyMark.top = mrk[0].top;		rCopyMark.bottom = mrk[0].bottom;
-	for(i = 1; i < nRec; i++) {
-		UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top);
-		UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom);
-		}
-	cTxtCur->bmCopyMark = new BitMapQT(rCopyMark.right - rCopyMark.left+1, 
-		rCopyMark.bottom - rCopyMark.top+1, out->hres, out->vres);
-}
-
-LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
-LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
-
-TxtCurBlink::TxtCurBlink():QObject(MainWidget, 0)
-{
-	isVis = false;
-	oCopyMark = 0L;		bmCopyMark = 0L;
-	count = cp_mark = 0;
-	startTimer(60);
-}
-
-void
-TxtCurBlink::Show()
-{
-	count = -4;
-	isVis = true;
-	if(bTxtCur && oTxtCur)oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
-
-}
-
-void
-TxtCurBlink::showCopyMark()
-{
-	if(bmCopyMark && oCopyMark) {
-		bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top, 
-			rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
-		bmCopyMark->SetLine(&liCopyMark1);
-		line[0].x = line[1].x = line[4].x = 0;
-		line[0].y = line[3].y = line[4].y = 0;
-		line[1].y = line[2].y = rCopyMark.bottom-rCopyMark.top-1;
-		line[2].x = line[3].x = rCopyMark.right-rCopyMark.left-1;
-		bmCopyMark->oPolyline(line, 5);
-		bmCopyMark->SetLine(&liCopyMark2);
-		bmCopyMark->RLP.finc = 1.0;		bmCopyMark->RLP.fp = (cp_mark & 0x7);
-		bmCopyMark->oPolyline(line, 5);
-		oCopyMark->ShowBitmap(rCopyMark.left, rCopyMark.top, bmCopyMark);
-		cp_mark++;
-		if(isVis && oTxtCur && ptTxtCurLine[0].y != ptTxtCurLine[1].y &&
-			oTxtCur == oCopyMark && OverlapRect(&rCopyMark, &rTxtCur)){
-			oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
-			}
-		}
-}
-
-void
-TxtCurBlink::timerEvent(QTimerEvent *ev)
-{
-	showCopyMark();
-	if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
-		ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return;
-	count++;
-	if(count<0) oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
-	if(count < 8) return;
-	count = 0;
-	if(bTxtCur && oTxtCur) {
-		if(isVis) {
-			oTxtCur->UpdateRect(&rTxtCur, false);
-			isVis = false;
-			}
-		else {
-			oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
-			isVis = true;
-			}
-		}
-}
+
+void Qt_Box()
+{
+	QMessageBox::aboutQt(QAppl->focusWidget(), "RLPlot uses Qt");
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Display blinking text cursor
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *oTxtCur = 0L;
+RECT rTxtCur, rCopyMark;
+bool bTxtCur = false;
+DWORD coTxtCur = 0x0L;
+TxtCurBlink *cTxtCur = 0L;
+POINT ptTxtCurLine[2];
+
+void HideTextCursor()
+{
+	if(oTxtCur) {
+		bTxtCur = false;
+		oTxtCur->UpdateRect(&rTxtCur, false);
+		}
+	oTxtCur = 0L;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+	if(oTxtCur && oTxtCur == out) HideTextCursor();
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+	coTxtCur = color;
+	HideTextCursor();
+	oTxtCur = out;
+	memcpy(&rTxtCur, disp, sizeof(RECT));
+	ptTxtCurLine[0].x = rTxtCur.left;	ptTxtCurLine[0].y = rTxtCur.top;
+	ptTxtCurLine[1].x = rTxtCur.right;	ptTxtCurLine[1].y = rTxtCur.bottom;
+	rTxtCur.bottom++;		rTxtCur.right++;
+	bTxtCur = true;
+	if(cTxtCur) cTxtCur->Show();
+}
+
+void InitTextCursor(bool init)
+{
+	if(init && !cTxtCur) cTxtCur = new TxtCurBlink();
+	else if(!init && cTxtCur) {
+		delete cTxtCur;
+		cTxtCur = 0L;
+		}
+}
+
+void HideCopyMark()
+{
+	if(cTxtCur && cTxtCur->bmCopyMark && cTxtCur->oCopyMark) {
+		cTxtCur->oCopyMark->UpdateRect(&rCopyMark, false);
+		delete cTxtCur->bmCopyMark;
+		}
+	cTxtCur->bmCopyMark = 0L;	cTxtCur->oCopyMark = 0L;
+}
+
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
+{
+	int i;
+
+	if(!out || !mrk || !nRec || !cTxtCur) return;
+	cTxtCur->oCopyMark = out;
+	rCopyMark.left = mrk[0].left;	rCopyMark.right = mrk[0].right;
+	rCopyMark.top = mrk[0].top;		rCopyMark.bottom = mrk[0].bottom;
+	for(i = 1; i < nRec; i++) {
+		UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top);
+		UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom);
+		}
+	cTxtCur->bmCopyMark = new BitMapQT(rCopyMark.right - rCopyMark.left+1, 
+		rCopyMark.bottom - rCopyMark.top+1, out->hres, out->vres);
+}
+
+LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
+LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
+
+TxtCurBlink::TxtCurBlink():QObject(MainWidget, 0)
+{
+	isVis = false;
+	oCopyMark = 0L;		bmCopyMark = 0L;
+	count = cp_mark = 0;
+	startTimer(60);
+}
+
+void
+TxtCurBlink::Show()
+{
+	count = -4;
+	isVis = true;
+	if(bTxtCur && oTxtCur)oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+
+}
+
+void
+TxtCurBlink::showCopyMark()
+{
+	if(bmCopyMark && oCopyMark) {
+		bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top, 
+			rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
+		bmCopyMark->SetLine(&liCopyMark1);
+		line[0].x = line[1].x = line[4].x = 0;
+		line[0].y = line[3].y = line[4].y = 0;
+		line[1].y = line[2].y = rCopyMark.bottom-rCopyMark.top-1;
+		line[2].x = line[3].x = rCopyMark.right-rCopyMark.left-1;
+		bmCopyMark->oPolyline(line, 5);
+		bmCopyMark->SetLine(&liCopyMark2);
+		bmCopyMark->RLP.finc = 1.0;		bmCopyMark->RLP.fp = (cp_mark & 0x7);
+		bmCopyMark->oPolyline(line, 5);
+		oCopyMark->ShowBitmap(rCopyMark.left, rCopyMark.top, bmCopyMark);
+		cp_mark++;
+		if(isVis && oTxtCur && ptTxtCurLine[0].y != ptTxtCurLine[1].y &&
+			oTxtCur == oCopyMark && OverlapRect(&rCopyMark, &rTxtCur)){
+			oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+			}
+		}
+}
+
+void
+TxtCurBlink::timerEvent(QTimerEvent *ev)
+{
+	showCopyMark();
+	if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
+		ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return;
+	count++;
+	if(count<0) oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+	if(count < 8) return;
+	count = 0;
+	if(bTxtCur && oTxtCur) {
+		if(isVis) {
+			oTxtCur->UpdateRect(&rTxtCur, false);
+			isVis = false;
+			}
+		else {
+			oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+			isVis = true;
+			}
+		}
+}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Clipboard support: the clipboard server uses sockets
@@ -550,11 +562,11 @@ RLPserver::GetRLP()
 
 #endif //RLP_PORT
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Process paste command: check for clipboard contents
-void TestClipboard(GraphObj *g)
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process paste command: check for clipboard contents
+void TestClipboard(GraphObj *g)
 {
-	if(!g) return;
+	if(!g) return;
 #ifdef RLP_PORT
 	if(rlpsrv && rlpsrv->SourceGO) {
 		if(rlpsrv->SourceGO->Id == GO_GRAPH || rlpsrv->SourceGO->Id == GO_PAGE)
@@ -564,11 +576,11 @@ void TestClipboard(GraphObj *g)
 		}
 	else new ReadCB(0, 0, g);
 #endif //RLP_PORT
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Copy spreadsheet or graph to clipboard
-void CopyData(GraphObj *g)
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Copy spreadsheet or graph to clipboard
+void CopyData(GraphObj *g)
 {
 	HideCopyMark();
 	QAppl->clipboard()->clear();
@@ -582,31 +594,31 @@ void CopyData(GraphObj *g)
 		}
 	else rlpsrv = new RLPserver(0, g);
 #endif //RLP_PORT
-}
-
-void CopyGraph(GraphObj *g)
+}
+
+void CopyGraph(GraphObj *g)
 {
 	if(g->Id == GO_PAGE && CurrGraph) CopyData(CurrGraph);
 	else CopyData(g);
-}
-
-void EmptyClip()
+}
+
+void EmptyClip()
 {
 #ifdef RLP_PORT
 	if(rlpsrv) {
 		delete(rlpsrv);			rlpsrv = 0;
 		}
-	else { 
-		QSocket *socket = new QSocket(0);
-		socket->connectToHost("localhost", RLP_PORT);
-		QTextStream os(socket);
-		os << "close\n";
-		socket->close();
-		}
+//	else { 
+//		QSocket *socket = new QSocket(0);
+//		socket->connectToHost("localhost", RLP_PORT);
+//		QTextStream os(socket);
+//		os << "close\n";
+//		socket->close();
+//		}
 #endif //RLP_PORT
-	HideCopyMark();
-	QAppl->clipboard()->clear();
-}
+	HideCopyMark();
+	QAppl->clipboard()->clear();
+}
 
 void CopyText(char *txt, int len)
 {
@@ -645,29 +657,29 @@ unsigned char* PasteText()
 		}
 	return tmp_txt;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get display (desktop) size
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void GetDesktopSize(int *width, int *height)
-{
-	QWidget *d = QApplication::desktop();
-	*width = d->width();
-	*height = d->height();
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Swap red and blue in RGB value
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-DWORD SwapRB(DWORD col)
-{
-	DWORD nc = col & 0x0000ff00L;
-
-	nc |= (col>>16)&0x000000ffL;
-	nc |= (col<<16)&0x00ff0000L;
-	return nc;
-}
-
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get display (desktop) size
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void GetDesktopSize(int *width, int *height)
+{
+	QWidget *d = QApplication::desktop();
+	*width = d->width();
+	*height = d->height();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Swap red and blue in RGB value
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DWORD SwapRB(DWORD col)
+{
+	DWORD nc = col & 0x0000ff00L;
+
+	nc |= (col>>16)&0x000000ffL;
+	nc |= (col<<16)&0x00ff0000L;
+	return nc;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Common code for all QT output classes
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -688,12 +700,9 @@ bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOut
 			else txt.append(QChar(ctxt[i]));
 			}
 		}
-	oldBrush = qP->brush();		dxf = qP->worldMatrix();
+	oldBrush = qP->brush();						dxf = qP->worldMatrix();
 	oldPen = currPen = qP->pen();
-	o->oGetTextExtent(ctxt, -1, &w, &h);
-	if(TxtSet->Align & TXA_VCENTER) iy = y + iround(TxtSet->iSize *0.4);
-	else if(TxtSet->Align & TXA_VBOTTOM) iy = y;
-	else iy = y + TxtSet->iSize + 1;
+	o->oGetTextExtent(ctxt, -1, &w, &h);		iy = y;
 	if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1);
 	else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
 	else ix = x;
@@ -711,8 +720,8 @@ bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOut
 			currPen.setColor(SwapRB(TxtSet->ColTxt));
 			qP->setPen(currPen);
 			}
-		if(TxtSet->Style & TXS_SUB) iy += o->un2iy(TxtSet->fSize*0.4);
-		else if(TxtSet->Style & TXS_SUPER) iy -= o->un2iy(TxtSet->fSize*0.4);
+		if(TxtSet->Style & TXS_SUB) iy += ((TxtSet->iSize <<2)/10);
+		else if(TxtSet->Style & TXS_SUPER) iy -= ((TxtSet->iSize <<2)/10);
 		qP->drawText(ix-x, iy-y, txt, -1);
 		}
 	else {
@@ -728,6 +737,8 @@ bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOut
 		else if(TxtSet->Style & TXS_SUPER) iy -= o->un2iy(TxtSet->fSize*0.4);
 		qP->drawText(ix, iy, txt, -1);
 		}
+	oldPen.setCapStyle(Qt::RoundCap);
+	oldPen.setJoinStyle(Qt::RoundJoin);
 	qP->setPen(oldPen);
 	qP->setBrush(oldBrush);
 	qP->setWorldMatrix(dxf, FALSE);
@@ -736,23 +747,18 @@ bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOut
 
 bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP)
 {
-	bool IsModified, RetVal;
+	bool RetVal;
 
 	if(!set->iSize && set->fSize > 0.0) set->iSize = o->un2iy(set->fSize);
 	if(!set->iSize) return false;
-	if(TxtSet->iSize != set->iSize || TxtSet->Style != set->Style ||
-		TxtSet->RotBL != set->RotBL || TxtSet->RotCHAR != set->RotCHAR ||
-		TxtSet->Font != set->Font || TxtSet->Mode != set->Mode)
-		IsModified = true;
-	else IsModified = false;
 	RetVal = o->anyOutput::SetTextSpec(set);
-	if(IsModified) {
+	if(true) {
 		qF.setBold((TxtSet->Style & TXS_BOLD) ? true : false);
 		qF.setItalic((TxtSet->Style & TXS_ITALIC) ? true : false);
 		qF.setUnderline((TxtSet->Style &TXS_UNDERLINE) ? true : false);
 		if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB))
-			 qF.setPointSize(o->un2iy(set->fSize*0.71));
-		else qF.setPointSize((TxtSet->iSize > 8) ? TxtSet->iSize : 8);
+			 qF.setPointSize((int)(TxtSet->iSize*0.71));
+		else qF.setPointSize((TxtSet->iSize > 2) ? TxtSet->iSize : 2);
 		switch(TxtSet->Font){
 		case FONT_HELVETICA:
 		default:			qF.setFamily("Helvetica");			break;
@@ -761,96 +767,97 @@ bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPai
 		case FONT_COURIER:	qF.setFamily("Courier");			break;
 			}
 		qP->setFont(qF);
+		if(TxtSet->fSize >0.0) TxtSet->iSize = o->un2iy(TxtSet->fSize);			//correct for printer
 		}
 	return RetVal;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Icon definitions
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//this icon has been taken from trolltech's Qt: qmessagebox.cpp
-static char *information_xpm[]={
-"32 32 5 1",
-". c None",
-"c c #000000",
-"* c #999999",
-"a c #ffffff",
-"b c #0000ff",
-"...........********.............",
-"........***aaaaaaaa***..........",
-"......**aaaaaaaaaaaaaa**........",
-".....*aaaaaaaaaaaaaaaaaa*.......",
-"....*aaaaaaaabbbbaaaaaaaac......",
-"...*aaaaaaaabbbbbbaaaaaaaac.....",
-"..*aaaaaaaaabbbbbbaaaaaaaaac....",
-".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
-".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
-"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
-"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
-"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
-"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
-"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
-"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
-"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
-".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
-".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
-"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
-"...caaaaaaabbbbbbbbbaaaaaac****.",
-"....caaaaaaaaaaaaaaaaaaaac****..",
-".....caaaaaaaaaaaaaaaaaac****...",
-"......ccaaaaaaaaaaaaaacc****....",
-".......*cccaaaaaaaaccc*****.....",
-"........***cccaaaac*******......",
-"..........****caaac*****........",
-".............*caaac**...........",
-"...............caac**...........",
-"................cac**...........",
-".................cc**...........",
-"..................***...........",
-"...................**..........."};
-
-//this icon has been taken from trolltech's Qt: qmessagebox.cpp
-static char *critical_xpm[]={
-"32 32 4 1",
-". c None",
-"a c #999999",
-"* c #ff0000",
-"b c #ffffff",
-"...........********.............",
-".........************...........",
-".......****************.........",
-"......******************........",
-".....********************a......",
-"....**********************a.....",
-"...************************a....",
-"..*******b**********b*******a...",
-"..******bbb********bbb******a...",
-".******bbbbb******bbbbb******a..",
-".*******bbbbb****bbbbb*******a..",
-"*********bbbbb**bbbbb*********a.",
-"**********bbbbbbbbbb**********a.",
-"***********bbbbbbbb***********aa",
-"************bbbbbb************aa",
-"************bbbbbb************aa",
-"***********bbbbbbbb***********aa",
-"**********bbbbbbbbbb**********aa",
-"*********bbbbb**bbbbb*********aa",
-".*******bbbbb****bbbbb*******aa.",
-".******bbbbb******bbbbb******aa.",
-"..******bbb********bbb******aaa.",
-"..*******b**********b*******aa..",
-"...************************aaa..",
-"....**********************aaa...",
-"....a********************aaa....",
-".....a******************aaa.....",
-"......a****************aaa......",
-".......aa************aaaa.......",
-".........aa********aaaaa........",
-"...........aaaaaaaaaaa..........",
-".............aaaaaaa............"};
-
-//thanks to Markus Bongard for the following icon
-static char *RLPlot_xpm[]={
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Icon definitions
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *information_xpm[]={
+"32 32 5 1",
+". c None",
+"c c #000000",
+"* c #999999",
+"a c #ffffff",
+"b c #0000ff",
+"...........********.............",
+"........***aaaaaaaa***..........",
+"......**aaaaaaaaaaaaaa**........",
+".....*aaaaaaaaaaaaaaaaaa*.......",
+"....*aaaaaaaabbbbaaaaaaaac......",
+"...*aaaaaaaabbbbbbaaaaaaaac.....",
+"..*aaaaaaaaabbbbbbaaaaaaaaac....",
+".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
+".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
+"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
+"...caaaaaaabbbbbbbbbaaaaaac****.",
+"....caaaaaaaaaaaaaaaaaaaac****..",
+".....caaaaaaaaaaaaaaaaaac****...",
+"......ccaaaaaaaaaaaaaacc****....",
+".......*cccaaaaaaaaccc*****.....",
+"........***cccaaaac*******......",
+"..........****caaac*****........",
+".............*caaac**...........",
+"...............caac**...........",
+"................cac**...........",
+".................cc**...........",
+"..................***...........",
+"...................**..........."};
+
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *critical_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #999999",
+"* c #ff0000",
+"b c #ffffff",
+"...........********.............",
+".........************...........",
+".......****************.........",
+"......******************........",
+".....********************a......",
+"....**********************a.....",
+"...************************a....",
+"..*******b**********b*******a...",
+"..******bbb********bbb******a...",
+".******bbbbb******bbbbb******a..",
+".*******bbbbb****bbbbb*******a..",
+"*********bbbbb**bbbbb*********a.",
+"**********bbbbbbbbbb**********a.",
+"***********bbbbbbbb***********aa",
+"************bbbbbb************aa",
+"************bbbbbb************aa",
+"***********bbbbbbbb***********aa",
+"**********bbbbbbbbbb**********aa",
+"*********bbbbb**bbbbb*********aa",
+".*******bbbbb****bbbbb*******aa.",
+".******bbbbb******bbbbb******aa.",
+"..******bbb********bbb******aaa.",
+"..*******b**********b*******aa..",
+"...************************aaa..",
+"....**********************aaa...",
+"....a********************aaa....",
+".....a******************aaa.....",
+"......a****************aaa......",
+".......aa************aaaa.......",
+".........aa********aaaaa........",
+"...........aaaaaaaaaaa..........",
+".............aaaaaaa............"};
+
+//thanks to Markus Bongard for the following icon
+static char *RLPlot_xpm[]={
 /* width height ncolors chars_per_pixel */
 "32 32 169 2",
 /* colors */
@@ -1057,553 +1064,565 @@ static char *RLPlot_xpm[]={
 "EGDDKEKEMEBFBFBFBFMEBFBFFEKEMEMEMEGEBFMEBFBFBFKEMEBFMEBFBFKEKEGI",
 "KJLHGINHGINHNHNHNHGINHNHGINHGINHNHGIGINHGINHNHGINHNHGIGINHNHGICJ"};
 
-//this icon has been taken from trolltech's Qt: qmessagebox.cpp
-static char *qtlogo_xpm[] = {
-/* width height ncolors chars_per_pixel */
-"50 50 17 1",
-/* colors */
-"  c #000000",
-". c #495808",
-"X c #2A3304",
-"o c #242B04",
-"O c #030401",
-"+ c #9EC011",
-"@ c #93B310",
-"# c #748E0C",
-"$ c #A2C511",
-"% c #8BA90E",
-"& c #99BA10",
-"* c #060701",
-"= c #181D02",
-"- c #212804",
-"; c #61770A",
-": c #0B0D01",
-"/ c None",
-/* pixels */
-"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$@;.o=::=o.;@$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$+#X*         **X#+$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$#oO*         O  **o#+$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$&.* OO              O*.&$$$$$$$$$$$$$",
-"$$$$$$$$$$$$@XOO            * OO    X&$$$$$$$$$$$$",
-"$$$$$$$$$$$@XO OO  O  **:::OOO OOO   X@$$$$$$$$$$$",
-"$$$$$$$$$$&XO      O-;#@++@%.oOO      X&$$$$$$$$$$",
-"$$$$$$$$$$.O  :  *-#+$$$$$$$$+#- : O O*.$$$$$$$$$$",
-"$$$$$$$$$#*OO  O*.&$$$$$$$$$$$$+.OOOO **#$$$$$$$$$",
-"$$$$$$$$+-OO O *;$$$$$$$$$$$&$$$$;*     o+$$$$$$$$",
-"$$$$$$$$#O*  O .+$$$$$$$$$$@X;$$$+.O    *#$$$$$$$$",
-"$$$$$$$$X*    -&$$$$$$$$$$@- :;$$$&-    OX$$$$$$$$",
-"$$$$$$$@*O  *O#$$$$$$$$$$@oOO**;$$$#    O*%$$$$$$$",
-"$$$$$$$;     -+$$$$$$$$$@o O OO ;+$$-O   *;$$$$$$$",
-"$$$$$$$.     ;$$$$$$$$$@-OO OO  X&$$;O    .$$$$$$$",
-"$$$$$$$o    *#$$$$$$$$@o  O O O-@$$$#O   *o$$$$$$$",
-"$$$$$$+=    *@$$$$$$$@o* OO   -@$$$$&:    =$$$$$$$",
-"$$$$$$+:    :+$$$$$$@-      *-@$$$$$$:    :+$$$$$$",
-"$$$$$$+:    :+$$$$$@o* O    *-@$$$$$$:    :+$$$$$$",
-"$$$$$$$=    :@$$$$@o*OOO      -@$$$$@:    =+$$$$$$",
-"$$$$$$$-    O%$$$@o* O O    O O-@$$$#*   OX$$$$$$$",
-"$$$$$$$. O *O;$$&o O*O* *O      -@$$;    O.$$$$$$$",
-"$$$$$$$;*   Oo+$$;O*O:OO--      Oo at +=    *;$$$$$$$",
-"$$$$$$$@*  O O#$$$;*OOOo@@-O     Oo;O*  **@$$$$$$$",
-"$$$$$$$$X* OOO-+$$$;O o@$$@-    O O     OX$$$$$$$$",
-"$$$$$$$$#*  * O.$$$$;X@$$$$@-O O        O#$$$$$$$$",
-"$$$$$$$$+oO O OO.+$$+&$$$$$$@-O         o+$$$$$$$$",
-"$$$$$$$$$#*    **.&$$$$$$$$$$@o      OO:#$$$$$$$$$",
-"$$$$$$$$$+.   O* O-#+$$$$$$$$+;O    OOO:@$$$$$$$$$",
-"$$$$$$$$$$&X  *O    -;#@++@#;=O    O    -@$$$$$$$$",
-"$$$$$$$$$$$&X O     O*O::::O      OO    Oo@$$$$$$$",
-"$$$$$$$$$$$$@XOO                  OO    O*X+$$$$$$",
-"$$$$$$$$$$$$$&.*       **  O      ::    *:#$$$$$$$",
-"$$$$$$$$$$$$$$$#o*OO       O    Oo#@-OOO=#$$$$$$$$",
-"$$$$$$$$$$$$$$$$+#X:* *     O**X#+$$@-*:#$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$%;.o=::=o.#@$$$$$$@X#$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$+$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/"};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bitmap class for display export etc.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput()
-{
-	int w, h;
-
-	hres = (double)hr;		vres = (double)vr;
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *qtlogo_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"50 50 17 1",
+/* colors */
+"  c #000000",
+". c #495808",
+"X c #2A3304",
+"o c #242B04",
+"O c #030401",
+"+ c #9EC011",
+"@ c #93B310",
+"# c #748E0C",
+"$ c #A2C511",
+"% c #8BA90E",
+"& c #99BA10",
+"* c #060701",
+"= c #181D02",
+"- c #212804",
+"; c #61770A",
+": c #0B0D01",
+"/ c None",
+/* pixels */
+"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$@;.o=::=o.;@$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$+#X*         **X#+$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$#oO*         O  **o#+$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$&.* OO              O*.&$$$$$$$$$$$$$",
+"$$$$$$$$$$$$@XOO            * OO    X&$$$$$$$$$$$$",
+"$$$$$$$$$$$@XO OO  O  **:::OOO OOO   X@$$$$$$$$$$$",
+"$$$$$$$$$$&XO      O-;#@++@%.oOO      X&$$$$$$$$$$",
+"$$$$$$$$$$.O  :  *-#+$$$$$$$$+#- : O O*.$$$$$$$$$$",
+"$$$$$$$$$#*OO  O*.&$$$$$$$$$$$$+.OOOO **#$$$$$$$$$",
+"$$$$$$$$+-OO O *;$$$$$$$$$$$&$$$$;*     o+$$$$$$$$",
+"$$$$$$$$#O*  O .+$$$$$$$$$$@X;$$$+.O    *#$$$$$$$$",
+"$$$$$$$$X*    -&$$$$$$$$$$@- :;$$$&-    OX$$$$$$$$",
+"$$$$$$$@*O  *O#$$$$$$$$$$@oOO**;$$$#    O*%$$$$$$$",
+"$$$$$$$;     -+$$$$$$$$$@o O OO ;+$$-O   *;$$$$$$$",
+"$$$$$$$.     ;$$$$$$$$$@-OO OO  X&$$;O    .$$$$$$$",
+"$$$$$$$o    *#$$$$$$$$@o  O O O-@$$$#O   *o$$$$$$$",
+"$$$$$$+=    *@$$$$$$$@o* OO   -@$$$$&:    =$$$$$$$",
+"$$$$$$+:    :+$$$$$$@-      *-@$$$$$$:    :+$$$$$$",
+"$$$$$$+:    :+$$$$$@o* O    *-@$$$$$$:    :+$$$$$$",
+"$$$$$$$=    :@$$$$@o*OOO      -@$$$$@:    =+$$$$$$",
+"$$$$$$$-    O%$$$@o* O O    O O-@$$$#*   OX$$$$$$$",
+"$$$$$$$. O *O;$$&o O*O* *O      -@$$;    O.$$$$$$$",
+"$$$$$$$;*   Oo+$$;O*O:OO--      Oo at +=    *;$$$$$$$",
+"$$$$$$$@*  O O#$$$;*OOOo@@-O     Oo;O*  **@$$$$$$$",
+"$$$$$$$$X* OOO-+$$$;O o@$$@-    O O     OX$$$$$$$$",
+"$$$$$$$$#*  * O.$$$$;X@$$$$@-O O        O#$$$$$$$$",
+"$$$$$$$$+oO O OO.+$$+&$$$$$$@-O         o+$$$$$$$$",
+"$$$$$$$$$#*    **.&$$$$$$$$$$@o      OO:#$$$$$$$$$",
+"$$$$$$$$$+.   O* O-#+$$$$$$$$+;O    OOO:@$$$$$$$$$",
+"$$$$$$$$$$&X  *O    -;#@++@#;=O    O    -@$$$$$$$$",
+"$$$$$$$$$$$&X O     O*O::::O      OO    Oo@$$$$$$$",
+"$$$$$$$$$$$$@XOO                  OO    O*X+$$$$$$",
+"$$$$$$$$$$$$$&.*       **  O      ::    *:#$$$$$$$",
+"$$$$$$$$$$$$$$$#o*OO       O    Oo#@-OOO=#$$$$$$$$",
+"$$$$$$$$$$$$$$$$+#X:* *     O**X#+$$@-*:#$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$%;.o=::=o.#@$$$$$$@X#$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$+$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/"};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bitmap class for display export etc.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput()
+{
+	int w, h;
+
+	hres = (double)hr;		vres = (double)vr;
 	image = 0L;				hgo = 0L;
-	if(wi) {
-		w = wi->width();		h = wi->height();
-		}
-	else {
-		GetDesktopSize(&w, &h);
-		}
-	Box1.Xmin = Box1.Ymin = 0.0;
-	Box1.Xmax = w;					Box1.Ymax = h;
-	DeskRect.left = DeskRect.top = 0;
-	GetDesktopSize(&w, &h);
-	DeskRect.right = w;				DeskRect.bottom = h;
-	mempic = new QPixmap(w, h);
-	mempic->fill(0x00ffffffL);
-	qPainter.begin(mempic);
-	qPen.setCapStyle(Qt::RoundCap);
-	qPainter.setPen(qPen);
-	qFont = qPainter.font();
-}
-
-BitMapQT::BitMapQT(int w, int h, double hr, double vr):anyOutput()
-{
-	hres = hr;		vres = vr;
+	if(wi) {
+		w = wi->width();		h = wi->height();
+		}
+	else {
+		GetDesktopSize(&w, &h);
+		}
+	Box1.Xmin = Box1.Ymin = 0.0;
+	Box1.Xmax = w;					Box1.Ymax = h;
+	DeskRect.left = DeskRect.top = 0;
+	GetDesktopSize(&w, &h);
+	DeskRect.right = w;				DeskRect.bottom = h;
+	mempic = new QPixmap(w, h);
+	mempic->fill(0x00ffffffL);
+	qPainter.begin(mempic);
+	qPen.setCapStyle(Qt::RoundCap);
+	qPen.setJoinStyle(Qt::RoundJoin);
+	qPainter.setPen(qPen);
+	qFont = qPainter.font();
+}
+
+BitMapQT::BitMapQT(int w, int h, double hr, double vr):anyOutput()
+{
+	hres = hr;		vres = vr;
 	image = 0L;		hgo = 0L;
-	w = abs(w);		h = abs(h);
-	Box1.Xmin = Box1.Ymin = 0.0;
-	Box1.Xmax = w;					Box1.Ymax = h;
-	DeskRect.right = w;				DeskRect.bottom = h;
-	DeskRect.left = DeskRect.top = 0;
-	mempic = new QPixmap(w, h);
-	mempic->fill(0x00ffffffL);
-	qPainter.begin(mempic);
-	qPen.setCapStyle(Qt::RoundCap);
-	qPainter.setPen(qPen);
-	qFont = qPainter.font();
-}
-
-BitMapQT::~BitMapQT()
-{
+	w = abs(w);		h = abs(h);
+	Box1.Xmin = Box1.Ymin = 0.0;
+	Box1.Xmax = w;					Box1.Ymax = h;
+	DeskRect.right = w;				DeskRect.bottom = h;
+	DeskRect.left = DeskRect.top = 0;
+	mempic = new QPixmap(w, h);
+	mempic->fill(0x00ffffffL);
+	qPainter.begin(mempic);
+	qPen.setCapStyle(Qt::RoundCap);
+	qPen.setJoinStyle(Qt::RoundJoin);
+	qPainter.setPen(qPen);
+	qFont = qPainter.font();
+}
+
+BitMapQT::~BitMapQT()
+{
 	Undo.KillDisp(this);
-	if(qPainter.isActive()) qPainter.end();
-	HideTextCursorObj(this);
-	if(mempic) delete mempic;
-	if(hgo) delete hgo;
-	if(image) delete image;
-	mempic = 0L;	hgo = 0L;	image = 0L;
-}
-
-bool
-BitMapQT::SetLine(LineDEF *lDef)
-{
-	int iw;
-
-	if(lDef->width != LineWidth || lDef->width != LineWidth ||
-		lDef->pattern != dPattern || lDef->color != dLineCol) {
-		LineWidth = lDef->width;
-		iw = iround(un2ix(lDef->width));
-		dPattern = lDef->pattern;
-		RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
-		RLP.fp = 0.0;
-		if(iLine == iw && dLineCol == lDef->color) return true;
-		iLine = iw;
-		dLineCol = lDef->color;
-		qPen.setColor(SwapRB(dLineCol));
-		qPen.setWidth(iw);
-		qPen.setStyle(Qt::SolidLine);
-		qPen.setCapStyle(Qt::RoundCap);
-		qPen.setJoinStyle(Qt::RoundJoin);
-		qPainter.setPen(qPen);
-		}
-	return true;
-}
-
-bool
-BitMapQT::SetFill(FillDEF *fill)
-{
-	if(!fill) return false;
-	if((fill->type & 0xff) != FILL_NONE) {
-		if(!hgo) hgo = new HatchOut(this);
-		if(hgo) hgo->SetFill(fill);
-		}
-	else {
-		if(hgo) delete hgo;
-		hgo = 0L;
-		}
-	qPainter.setBrush(QColor(SwapRB(fill->color)));
-	dFillCol = fill->color;
-	dFillCol2 = fill->color2;
-	return true;
-}
-
-bool
-BitMapQT::SetTextSpec(TextDEF *set)
+	if(qPainter.isActive()) qPainter.end();
+	HideTextCursorObj(this);
+	if(mempic) delete mempic;
+	if(hgo) delete hgo;
+	if(image) delete image;
+	mempic = 0L;	hgo = 0L;	image = 0L;
+}
+
+bool
+BitMapQT::SetLine(LineDEF *lDef)
 {
-	return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter);
-}
-
-bool
-BitMapQT::Erase(DWORD color)
-{
-	if(!mempic) return false;
-	mempic->fill(color);
-	if(image) delete image;
-	image = 0L;
-	return true;
-}
-
-bool
-BitMapQT::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
-	int sw, int sh, bool invert)
-{
-	BitMapQT *src = (BitMapQT*)sr;
-
-	if(!mempic) return false;
-	bitBlt(mempic, x, y, src->mempic, sx, sy, sw, sh,
-		invert ? Qt::NotCopyROP : Qt::CopyROP);
-	return true;
-
-
-}
-
-bool
-BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height)
-{
-	if(!text) return false;
-	QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
-		text, cb > 0 ? cb : strlen(text));
-	*width = rc.rRight() - rc.rLeft();		*height = TxtSet.iSize +2;
-	return true;
-}
-
-bool
-BitMapQT::oGetPix(int x, int y, DWORD *col)
-{
-	DWORD pix;
-
-	if(!image && !(image = new QImage(mempic->convertToImage())))return false;
-	if(x >= DeskRect.left && x < DeskRect.right &&
-		y >= DeskRect.top && y < DeskRect.bottom){
-		pix = SwapRB(image->pixel(x, y));
-		*col = pix;
-		return true;
-		}
-	return false;
-}
-
-bool
-BitMapQT::oDrawIcon(int type, int x, int y)
-{
-	char** xpm_data;
-	QPixmap pm;
-
-	switch (type) {
-	case ICO_INFO:
-		xpm_data = information_xpm;
-		break;
-	case ICO_ERROR:
-		xpm_data = critical_xpm;
-		break;
-	case ICO_RLPLOT:
-		xpm_data = RLPlot_xpm;
-		break;
-	case ICO_QT:
-		xpm_data = qtlogo_xpm;
-		break;
-	default:
-		return false;
-		}
-	if (xpm_data) {
-		QImage image((const char **)xpm_data);
-		pm.convertFromImage(image);
-		bitBlt(mempic, x, y, &pm, 0, 0,	-1, -1, Qt::CopyROP);
-		return true;
-		}
-	return false;
-}
-
-bool
-BitMapQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
-{
-	qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
-	if(hgo) return hgo->oCircle(x1, y1, x2, y2);
-	return true;
-}
-
-bool
-BitMapQT::oPolyline(POINT * pts, int cp, char *nam)
-{
-	int i;
-
-	if(cp < 1) return false;
-	if (dPattern) {
-		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
-		}
-	else {
-		qPainter.moveTo(pts[0].x, pts[0].y);
-		for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
-		}
-	return true;
-}
-
-bool
-BitMapQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
-{
-	qPainter.drawRect(x1, y1, x2-x1, y2-y1);
-	if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
-	return true;
-}
-
-bool
-BitMapQT::oSolidLine(POINT *p)
-{
-	qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
-	return true;
-}
-
-bool
-BitMapQT::oTextOut(int x, int y, char *txt, int cb)
-{
-	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
-}
-
-bool
-BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
-{
-	int i;
-
-	QPointArray *a;
-
-	if(!pts || cp <2) return false;
-	a = new QPointArray(cp);
-	if (a) {
-		for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
-		qPainter.drawPolygon(*a);
-		delete a;
-		}
-	if(hgo) hgo->oPolygon(pts, cp);
-}
-
-bool
-BitMapQT::oArc(int x1, int y1, int x2, int y2, int quads)
-{
-	int i, j;
-
-	if(x1 > x2) Swap(x1, x2);	if(y1 > y2) Swap(y1, y2);
-	switch(quads) {
-	case 1:	i = 270*16;		j = 90*16;	break;
-	case 2:	i = 180*16;		j = 180*16;	break;
-	case 3:	i = 90*16;		j = 270*16;	break;
-	case 4:	i = 0;			j = 360*16;	break;
-	default: return false;
-		}
-	qPainter.drawArc(x1, y1, x2-x1, y2-y1, i, j);
-	return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The display output class
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-OutputQT::OutputQT(GraphObj *g):BitMapQT(g, 0L)
-{
-	int w, h;
-	RLPwidget *rw;
-
-	HScroll = VScroll = 0L;
-	CreateNewWindow(BaseObj = g);
-	if(rw = (RLPwidget*)widget) {
-		rw->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
-		rw->show();
-		rw->mempic = mempic;
-		rw->setBackgroundMode(QWidget::NoBackground);
-		}
-}
-
-OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
-{
-	//assume fixed size (dialog) widget
-	widget = wi;
-	HScroll = VScroll = 0L;
-	BaseObj = 0L;
-	wi->OutputClass = this;
-	wi->mempic = mempic;
-	wi->setBackgroundMode(QWidget::NoBackground);
-	xAxis.flags = 0L;
-	yAxis.flags = AXIS_INVERT;	//drawing origin upper left corner
-}
-
-OutputQT::~OutputQT()
-{
-	if(qPainter.isActive()) qPainter.end();
-	if(widget)	delete widget;	widget = 0L;
-	HideTextCursorObj(this);
-	if(mempic) delete mempic;	mempic = 0L;
-	if(hgo) delete hgo;			hgo = 0L;
-	if(image) delete image;		image = 0L;
-}
-
-bool
-OutputQT::ActualSize(RECT *rc)
-{
-	if(rc) {
-		rc->left = rc->top = 0;
-		rc->bottom = widget->height() - MenuHeight-6;
-		rc->right = widget->width();
-		return true;
-		}
-	return false;
-}
-
-void
-OutputQT::Caption(char *txt)
-{
-	QString cap(txt);
-	widget->setCaption(cap);
-}
-
-unsigned char hand_bits[] =	{	//hand cursor bitmap
-	0x80, 0x01, 0x58, 0x0e, 0x64, 0x12, 0x64, 0x52,
-	0x48, 0xb2, 0x48, 0x92, 0x16, 0x90, 0x19, 0x80,
-	0x11, 0x40, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20,
-	0x08, 0x20, 0x10, 0x10, 0x20, 0x10, 0x20, 0x10};
-
-unsigned char hand_mask[] =	{	//hand cursor mask
-	0x80, 0x01, 0xd8, 0x0f, 0xfc, 0x1f, 0xfc, 0x5f,
-	0xf8, 0xbf, 0xf8, 0xff, 0xfe, 0xff, 0xff, 0xff,
-	0xff, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f,
-	0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0, 0x1f};
-
-unsigned char zoom_bits[] =	{	//zoom cursor bitmap
-	0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x60, 0x0a,
-	0x10, 0x10, 0x08, 0x21, 0x08, 0x21, 0x04, 0x40,
-	0x64, 0x4c, 0x04, 0x40, 0x08, 0x21, 0x08, 0x21,
-	0x10, 0x10, 0x60, 0x0a, 0x80, 0x03, 0x00, 0x00};
-
-unsigned char zoom_mask[] =	{	//zoom cursor mask
-	0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f,
-	0xf0, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf4, 0x7e,
-	0x7c, 0x7c, 0xfc, 0x7e, 0xf8, 0x3f, 0xf8, 0x3f,
-	0xf0, 0x1f, 0xe0, 0x0f, 0x80, 0x03, 0x00, 0x00};
+	int iw;
 
-unsigned char paste_bits[] = {	//paste cursor bitmap
-	0x04, 0x00,	0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0xc4, 0x7f, 0x20, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
-	0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80,
-	0x20, 0x80, 0x20, 0x80, 0xc0, 0x7f, 0x00, 0x00};
+	if(lDef->width != LineWidth || lDef->width != LineWidth ||
+		lDef->pattern != dPattern || lDef->color != dLineCol) {
+		LineWidth = lDef->width;
+		iw = iround(un2ix(lDef->width));
+		dPattern = lDef->pattern;
+		RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+		RLP.fp = 0.0;
+		if(iLine == iw && dLineCol == lDef->color) return true;
+		iLine = iw;
+		dLineCol = lDef->color;
+		qPen.setColor(SwapRB(dLineCol));
+		qPen.setWidth(iw);
+		qPen.setStyle(Qt::SolidLine);
+		qPen.setCapStyle(Qt::RoundCap);
+		qPen.setJoinStyle(Qt::RoundJoin);
+		qPainter.setPen(qPen);
+		}
+	return true;
+}
 
-unsigned char paste_mask[] = {	//paste cursor mask
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0xc4, 0x7f, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
-	0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
-	0xe0, 0xff, 0xe0, 0xff, 0xc0, 0x7f, 0x00, 0x00};
+bool
+BitMapQT::SetFill(FillDEF *fill)
+{
+	if(!fill) return false;
+	if((fill->type & 0xff) != FILL_NONE) {
+		if(!hgo) hgo = new HatchOut(this);
+		if(hgo) hgo->SetFill(fill);
+		}
+	else {
+		if(hgo) delete hgo;
+		hgo = 0L;
+		}
+	qPainter.setBrush(QColor(SwapRB(fill->color)));
+	dFillCol = fill->color;
+	dFillCol2 = fill->color2;
+	return true;
+}
 
-unsigned char drawpen_bits[] = {	//draw cursor bitmap
-	0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xce, 0x00,
-	0x04, 0x01, 0x44, 0x02, 0x88, 0x04, 0x08, 0x09,
-	0x10, 0x12, 0x20, 0x24, 0x40, 0x48, 0x80, 0xd0,
-	0x00, 0xe1, 0x00, 0x72, 0x00, 0x3c, 0x00, 0x18};
+bool
+BitMapQT::SetTextSpec(TextDEF *set)
+{
+	return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter);
+}
 
-unsigned char drawpen_mask[] = {	//draw cursor mask
-	0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xfe, 0x00,
-	0xfc, 0x01, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x0f,
-	0xf0, 0x1f, 0xe0, 0x3f, 0xc0, 0x7f, 0x80, 0xff,
-	0x00, 0xff, 0x00, 0x7e, 0x00, 0x3c, 0x00, 0x18};
+bool
+BitMapQT::Erase(DWORD color)
+{
+	if(!mempic) return false;
+	mempic->fill(color);
+	if(image) delete image;
+	image = 0L;
+	return true;
+}
 
-unsigned char drect_bits[] = {	//draw rectangle bitmap
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x08, 0x80,
-	0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
-	0x08, 0x80, 0x08, 0x80, 0xf8, 0xff, 0x00, 0x00};
+bool
+BitMapQT::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
+	int sw, int sh, bool invert)
+{
+	BitMapQT *src = (BitMapQT*)sr;
 
-unsigned char drect_mask[] = {	//draw rectangle mask
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf8, 0xff,
-	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
-	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x00, 0x00};
+	if(!mempic) return false;
+	bitBlt(mempic, x, y, src->mempic, sx, sy, sw, sh,
+		invert ? Qt::NotCopyROP : Qt::CopyROP);
+	return true;
 
-unsigned char drrect_bits[] = {	//draw rounded rectangle bitmap
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x10, 0x40,
-	0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
-	0x08, 0x80, 0x10, 0x40, 0xe0, 0x3f, 0x00, 0x00};
 
-unsigned char drrect_mask[] = {	//draw rounded rectangle mask
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0xf0, 0x7f,
-	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
-	0xf8, 0xff, 0xf0, 0x7f, 0xe0, 0x3f, 0x00, 0x00};
+}
 
-unsigned char delly_bits[] = {	//draw ellipse bitmap
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x60, 0x30,
-	0x10, 0x40, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
-	0x10, 0x40, 0x60, 0x30, 0x80, 0x0f, 0x00, 0x00};
+bool
+BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	if(!text || !text[0]){
+		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, "A", 1);
+		*width = rc.rLeft();
+		}
+	else {
+		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
+		text, cb > 0 ? cb : strlen(text));
+		*width = rc.rRight() - rc.rLeft();
+		}
+	*height = TxtSet.iSize +2;
+	return true;
+}
 
-unsigned char delly_mask[] = {	//draw ellipse mask
-	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
-	0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xe0, 0x3f,
-	0xf0, 0x7f, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
-	0xf0, 0x7f, 0xe0, 0x3f, 0x80, 0x0f, 0x00, 0x00};
-
-//display 16x16 cursor data: developers utility
-/*
-void disp_bm(unsigned char *tb)
+bool
+BitMapQT::oGetPix(int x, int y, DWORD *col)
 {
-	char txt[512];
-	unsigned char currbyte;
-	int i, j, pos;
+	DWORD pix;
 
-	for(i = pos = 0; i < 32; i++) {
-		currbyte = tb[i];
-		for (j = 0; j < 8; j++) {
-			if(currbyte & 0x01) pos += sprintf(txt+pos, "1");
-			else pos += sprintf(txt+pos, "0");
-			currbyte >>= 1;
-			}
-		if(i & 1)pos += sprintf(txt+pos, "\n");
+	if(!image && !(image = new QImage(mempic->convertToImage())))return false;
+	if(x >= DeskRect.left && x < DeskRect.right &&
+		y >= DeskRect.top && y < DeskRect.bottom){
+		pix = SwapRB(image->pixel(x, y));
+		*col = pix;
+		return true;
 		}
-	InfoBox(txt);
+	return false;
 }
-*/
 
-void
-OutputQT::MouseCursor(int cid, bool force)
-{
-	if(cid == cCursor && !force) return;
-	if(cid == MC_LAST) cid = cCursor;
-	QBitmap *bits, *mask;
-	bits = mask = 0L;
+bool
+BitMapQT::oDrawIcon(int type, int x, int y)
+{
+	char** xpm_data;
+	QPixmap pm;
 
-	switch(cid) {
-#ifdef Q_CHECK_PTR				//Qt version 3
-	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
-	case MC_CROSS:	widget->setCursor(QCursor(Qt::CrossCursor));	break;
-	case MC_WAIT:	widget->setCursor(QCursor(Qt::WaitCursor));		break;
-	case MC_TEXT:	widget->setCursor(QCursor(Qt::IbeamCursor));	break;
-	case MC_NORTH:	widget->setCursor(QCursor(Qt::SizeVerCursor));	break;
-	case MC_NE:		widget->setCursor(QCursor(Qt::SizeBDiagCursor));break;
-	case MC_EAST:	widget->setCursor(QCursor(Qt::SizeHorCursor));	break;
-	case MC_SE:		widget->setCursor(QCursor(Qt::SizeFDiagCursor));break;
-	case MC_SALL:	widget->setCursor(QCursor(Qt::SizeAllCursor));	break;
-#else							//Qt version 2
-	case MC_ARROW:	widget->setCursor(QCursor(ArrowCursor));	break;
-	case MC_CROSS:	widget->setCursor(QCursor(CrossCursor));	break;
-	case MC_WAIT:	widget->setCursor(QCursor(WaitCursor));		break;
-	case MC_TEXT:	widget->setCursor(QCursor(IbeamCursor));	break;
-	case MC_NORTH:	widget->setCursor(QCursor(SizeVerCursor));	break;
-	case MC_NE:		widget->setCursor(QCursor(SizeBDiagCursor));break;
-	case MC_EAST:	widget->setCursor(QCursor(SizeHorCursor));	break;
-	case MC_SE:		widget->setCursor(QCursor(SizeFDiagCursor));break;
-	case MC_SALL:	widget->setCursor(QCursor(SizeAllCursor));	break;
-#endif
-	case MC_MOVE:
-		bits = new QBitmap(16, 16, hand_bits, TRUE);
-		mask = new QBitmap(16, 16, hand_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 7, 7));
-		break;
-	case MC_ZOOM:
-		bits = new QBitmap(16, 16, zoom_bits, TRUE);
-		mask = new QBitmap(16, 16, zoom_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 7, 7));
-		break;
-	case MC_PASTE:
-		bits = new QBitmap(16, 16, paste_bits, TRUE);
-		mask = new QBitmap(16, 16, paste_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 2, 2));
+	switch (type) {
+	case ICO_INFO:
+		xpm_data = information_xpm;
+		break;
+	case ICO_ERROR:
+		xpm_data = critical_xpm;
+		break;
+	case ICO_RLPLOT:
+		xpm_data = RLPlot_xpm;
+		break;
+	case ICO_QT:
+		xpm_data = qtlogo_xpm;
+		break;
+	default:
+		return false;
+		}
+	if (xpm_data) {
+		QImage image((const char **)xpm_data);
+		pm.convertFromImage(image);
+		bitBlt(mempic, x, y, &pm, 0, 0,	-1, -1, Qt::CopyROP);
+		return true;
+		}
+	return false;
+}
+
+bool
+BitMapQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+	qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
+	if(hgo) return hgo->oCircle(x1, y1, x2, y2);
+	return true;
+}
+
+bool
+BitMapQT::oPolyline(POINT * pts, int cp, char *nam)
+{
+	int i;
+
+	if(cp < 1) return false;
+	if (dPattern) {
+		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+		}
+	else {
+		qPainter.moveTo(pts[0].x, pts[0].y);
+		for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
+		}
+	return true;
+}
+
+bool
+BitMapQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+	qPainter.drawRect(x1, y1, x2-x1, y2-y1);
+	if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
+	return true;
+}
+
+bool
+BitMapQT::oSolidLine(POINT *p)
+{
+	qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
+	return true;
+}
+
+bool
+BitMapQT::oTextOut(int x, int y, char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	if(TxtSet.Align & TXA_VCENTER) y += iround(TxtSet.iSize * 0.4);
+	else if(TxtSet.Align & TXA_VBOTTOM) y -= iround(TxtSet.iSize * 0.1);
+	else y += iround(TxtSet.iSize * 1.0);
+	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+	int i;
+
+	QPointArray *a;
+
+	if(!pts || cp <2) return false;
+	a = new QPointArray(cp);
+	if (a) {
+		for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
+		qPainter.drawPolygon(*a);
+		delete a;
+		}
+	if(hgo) hgo->oPolygon(pts, cp);
+}
+
+bool
+BitMapQT::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+	int i, j;
+
+	if(x1 > x2) Swap(x1, x2);	if(y1 > y2) Swap(y1, y2);
+	switch(quads) {
+	case 1:	i = 270*16;		j = 90*16;	break;
+	case 2:	i = 180*16;		j = 180*16;	break;
+	case 3:	i = 90*16;		j = 270*16;	break;
+	case 4:	i = 0;			j = 360*16;	break;
+	default: return false;
+		}
+	qPainter.drawArc(x1, y1, x2-x1, y2-y1, i, j);
+	return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The display output class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+OutputQT::OutputQT(GraphObj *g):BitMapQT(g, 0L)
+{
+	int w, h;
+	RLPwidget *rw;
+
+	HScroll = VScroll = 0L;
+	CreateNewWindow(BaseObj = g);
+	if(rw = (RLPwidget*)widget) {
+		rw->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
+		rw->show();
+		rw->mempic = mempic;
+		rw->setBackgroundMode(QWidget::NoBackground);
+		}
+}
+
+OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
+{
+	//assume fixed size (dialog) widget
+	widget = wi;
+	HScroll = VScroll = 0L;
+	BaseObj = 0L;
+	wi->OutputClass = this;
+	wi->mempic = mempic;
+	wi->setBackgroundMode(QWidget::NoBackground);
+	xAxis.flags = 0L;
+	yAxis.flags = AXIS_INVERT;	//drawing origin upper left corner
+}
+
+OutputQT::~OutputQT()
+{
+	if(qPainter.isActive()) qPainter.end();
+	if(widget)	delete widget;	widget = 0L;
+	HideTextCursorObj(this);
+	if(mempic) delete mempic;	mempic = 0L;
+	if(hgo) delete hgo;			hgo = 0L;
+	if(image) delete image;		image = 0L;
+}
+
+bool
+OutputQT::ActualSize(RECT *rc)
+{
+	if(rc) {
+		rc->left = rc->top = 0;
+		rc->bottom = widget->height() - MenuHeight-6;
+		rc->right = widget->width();
+		return true;
+		}
+	return false;
+}
+
+void
+OutputQT::Caption(char *txt)
+{
+	QString cap(txt);
+	widget->setCaption(cap);
+}
+
+unsigned char hand_bits[] =	{	//hand cursor bitmap
+	0x80, 0x01, 0x58, 0x0e, 0x64, 0x12, 0x64, 0x52,
+	0x48, 0xb2, 0x48, 0x92, 0x16, 0x90, 0x19, 0x80,
+	0x11, 0x40, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20,
+	0x08, 0x20, 0x10, 0x10, 0x20, 0x10, 0x20, 0x10};
+
+unsigned char hand_mask[] =	{	//hand cursor mask
+	0x80, 0x01, 0xd8, 0x0f, 0xfc, 0x1f, 0xfc, 0x5f,
+	0xf8, 0xbf, 0xf8, 0xff, 0xfe, 0xff, 0xff, 0xff,
+	0xff, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f,
+	0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0, 0x1f};
+
+unsigned char zoom_bits[] =	{	//zoom cursor bitmap
+	0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x60, 0x0a,
+	0x10, 0x10, 0x08, 0x21, 0x08, 0x21, 0x04, 0x40,
+	0x64, 0x4c, 0x04, 0x40, 0x08, 0x21, 0x08, 0x21,
+	0x10, 0x10, 0x60, 0x0a, 0x80, 0x03, 0x00, 0x00};
+
+unsigned char zoom_mask[] =	{	//zoom cursor mask
+	0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f,
+	0xf0, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf4, 0x7e,
+	0x7c, 0x7c, 0xfc, 0x7e, 0xf8, 0x3f, 0xf8, 0x3f,
+	0xf0, 0x1f, 0xe0, 0x0f, 0x80, 0x03, 0x00, 0x00};
+
+unsigned char paste_bits[] = {	//paste cursor bitmap
+	0x04, 0x00,	0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0xc4, 0x7f, 0x20, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
+	0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80,
+	0x20, 0x80, 0x20, 0x80, 0xc0, 0x7f, 0x00, 0x00};
+
+unsigned char paste_mask[] = {	//paste cursor mask
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0xc4, 0x7f, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
+	0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
+	0xe0, 0xff, 0xe0, 0xff, 0xc0, 0x7f, 0x00, 0x00};
+
+unsigned char drawpen_bits[] = {	//draw cursor bitmap
+	0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xce, 0x00,
+	0x04, 0x01, 0x44, 0x02, 0x88, 0x04, 0x08, 0x09,
+	0x10, 0x12, 0x20, 0x24, 0x40, 0x48, 0x80, 0xd0,
+	0x00, 0xe1, 0x00, 0x72, 0x00, 0x3c, 0x00, 0x18};
+
+unsigned char drawpen_mask[] = {	//draw cursor mask
+	0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xfe, 0x00,
+	0xfc, 0x01, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x0f,
+	0xf0, 0x1f, 0xe0, 0x3f, 0xc0, 0x7f, 0x80, 0xff,
+	0x00, 0xff, 0x00, 0x7e, 0x00, 0x3c, 0x00, 0x18};
+
+unsigned char drect_bits[] = {	//draw rectangle bitmap
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x08, 0x80,
+	0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
+	0x08, 0x80, 0x08, 0x80, 0xf8, 0xff, 0x00, 0x00};
+
+unsigned char drect_mask[] = {	//draw rectangle mask
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf8, 0xff,
+	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
+	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x00, 0x00};
+
+unsigned char drrect_bits[] = {	//draw rounded rectangle bitmap
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x10, 0x40,
+	0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
+	0x08, 0x80, 0x10, 0x40, 0xe0, 0x3f, 0x00, 0x00};
+
+unsigned char drrect_mask[] = {	//draw rounded rectangle mask
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0xf0, 0x7f,
+	0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
+	0xf8, 0xff, 0xf0, 0x7f, 0xe0, 0x3f, 0x00, 0x00};
+
+unsigned char delly_bits[] = {	//draw ellipse bitmap
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x60, 0x30,
+	0x10, 0x40, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80,
+	0x10, 0x40, 0x60, 0x30, 0x80, 0x0f, 0x00, 0x00};
+
+unsigned char delly_mask[] = {	//draw ellipse mask
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xe0, 0x3f,
+	0xf0, 0x7f, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff,
+	0xf0, 0x7f, 0xe0, 0x3f, 0x80, 0x0f, 0x00, 0x00};
+
+//display 16x16 cursor data: developers utility
+/*
+void disp_bm(unsigned char *tb)
+{
+	char txt[512];
+	unsigned char currbyte;
+	int i, j, pos;
+
+	for(i = pos = 0; i < 32; i++) {
+		currbyte = tb[i];
+		for (j = 0; j < 8; j++) {
+			if(currbyte & 0x01) pos += sprintf(txt+pos, "1");
+			else pos += sprintf(txt+pos, "0");
+			currbyte >>= 1;
+			}
+		if(i & 1)pos += sprintf(txt+pos, "\n");
+		}
+	InfoBox(txt);
+}
+*/
+
+void
+OutputQT::MouseCursor(int cid, bool force)
+{
+	if(cid == cCursor && !force) return;
+	if(cid == MC_LAST) cid = cCursor;
+	QBitmap *bits, *mask;
+	bits = mask = 0L;
+
+	switch(cid) {
+#ifdef Q_CHECK_PTR				//Qt version 3
+	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
+	case MC_CROSS:	widget->setCursor(QCursor(Qt::CrossCursor));	break;
+	case MC_WAIT:	widget->setCursor(QCursor(Qt::WaitCursor));		break;
+	case MC_TEXT:	widget->setCursor(QCursor(Qt::IbeamCursor));	break;
+	case MC_NORTH:	widget->setCursor(QCursor(Qt::SizeVerCursor));	break;
+	case MC_NE:		widget->setCursor(QCursor(Qt::SizeBDiagCursor));break;
+	case MC_EAST:	widget->setCursor(QCursor(Qt::SizeHorCursor));	break;
+	case MC_SE:		widget->setCursor(QCursor(Qt::SizeFDiagCursor));break;
+	case MC_SALL:	widget->setCursor(QCursor(Qt::SizeAllCursor));	break;
+#else							//Qt version 2
+	case MC_ARROW:	widget->setCursor(QCursor(ArrowCursor));	break;
+	case MC_CROSS:	widget->setCursor(QCursor(CrossCursor));	break;
+	case MC_WAIT:	widget->setCursor(QCursor(WaitCursor));		break;
+	case MC_TEXT:	widget->setCursor(QCursor(IbeamCursor));	break;
+	case MC_NORTH:	widget->setCursor(QCursor(SizeVerCursor));	break;
+	case MC_NE:		widget->setCursor(QCursor(SizeBDiagCursor));break;
+	case MC_EAST:	widget->setCursor(QCursor(SizeHorCursor));	break;
+	case MC_SE:		widget->setCursor(QCursor(SizeFDiagCursor));break;
+	case MC_SALL:	widget->setCursor(QCursor(SizeAllCursor));	break;
+#endif
+	case MC_MOVE:
+		bits = new QBitmap(16, 16, hand_bits, TRUE);
+		mask = new QBitmap(16, 16, hand_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 7, 7));
+		break;
+	case MC_ZOOM:
+		bits = new QBitmap(16, 16, zoom_bits, TRUE);
+		mask = new QBitmap(16, 16, zoom_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 7, 7));
+		break;
+	case MC_PASTE:
+		bits = new QBitmap(16, 16, paste_bits, TRUE);
+		mask = new QBitmap(16, 16, paste_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 2, 2));
 		break;
 	case MC_DRAWPEN:
 		bits = new QBitmap(16, 16, drawpen_bits, TRUE);
@@ -1625,447 +1644,453 @@ OutputQT::MouseCursor(int cid, bool force)
 		mask = new QBitmap(16, 16, delly_mask, TRUE);
 		widget->setCursor(QCursor(*bits, *mask, 2, 2));
 		break;
-	default:	return;
-		}
-	if(bits) delete bits;		if(mask) delete mask;
-	cCursor = cid;
-}
-
-bool
-OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
-{
-	QScrollBar *sb;
-
-	if(isVert) {
-		if(!(sb = VScroll))return false;
-		}
-	else if(!(sb = HScroll)) return false;
-	if(iPos < sb->minValue()) return false;
-	sb->setRange(iMin, iMax);
-	sb->setPageStep(iPSize);
-	if(BaseObj && BaseObj->Id == GO_GRAPH) sb->setLineStep(8);
-	else sb->setLineStep(1);
-	sb->setValue(iPos);
-	return true;
-}
-
-bool
-OutputQT::EndPage()
-{
-	if(widget)widget->repaint();
-	return true;
-}
-
-bool
-OutputQT::UpdateRect(RECT *rc, bool invert)
-{
-	int x1, x2, y1, y2;
-
-	if(!widget || !mempic)return false;
-	if(rc->right > rc->left) {
-		x1 = rc->left;		x2 = rc->right;
-		}
-	else {
-		x1 = rc->right;		x2 = rc->left;
-		}
-	if(rc->bottom > rc->top) {
-		y1 = rc->top;		y2 = rc->bottom;
-		}
-	else {
-		y1 = rc->bottom;	y2 = rc->top;
-		}
-	if(x2 > DeskRect.right) x2 = DeskRect.right;
+	default:	return;
+		}
+	if(bits) delete bits;		if(mask) delete mask;
+	cCursor = cid;
+}
+
+bool
+OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
+{
+	QScrollBar *sb;
+
+	if(isVert) {
+		if(!(sb = VScroll))return false;
+		}
+	else if(!(sb = HScroll)) return false;
+	if(iPos < sb->minValue()) return false;
+	sb->setRange(iMin, iMax);
+	sb->setPageStep(iPSize);
+	if(BaseObj && BaseObj->Id == GO_GRAPH) sb->setLineStep(8);
+	else sb->setLineStep(1);
+	sb->setValue(iPos);
+	return true;
+}
+
+bool
+OutputQT::EndPage()
+{
+	if(widget)widget->repaint();
+	return true;
+}
+
+bool
+OutputQT::UpdateRect(RECT *rc, bool invert)
+{
+	int x1, x2, y1, y2;
+
+	if(!widget || !mempic)return false;
+	if(rc->right > rc->left) {
+		x1 = rc->left;		x2 = rc->right;
+		}
+	else {
+		x1 = rc->right;		x2 = rc->left;
+		}
+	if(rc->bottom > rc->top) {
+		y1 = rc->top;		y2 = rc->bottom;
+		}
+	else {
+		y1 = rc->bottom;	y2 = rc->top;
+		}
+	if(x2 > DeskRect.right) x2 = DeskRect.right;
 	if(y2 > DeskRect.bottom) y2 = DeskRect.right;
-	bitBlt(widget, x1, y1, mempic, x1, y1,
-		x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP);
-	return true;
-}
-
-void
-OutputQT::ShowBitmap(int x, int y, anyOutput* src)
-{
-	BitMapQT *sr;
-	RECT *rc;
-
-	if(!widget || !mempic || !src)return;
-	sr = (BitMapQT*) src;		rc = &sr->DeskRect;
-	bitBlt(widget, x, y, sr->mempic, 0, 0, abs(rc->right-rc->left), 
-		abs(rc->bottom-rc->top), Qt::CopyROP);
-}
-
-void
-OutputQT::ShowLine(POINT * pts, int cp, DWORD color)
-{
-	int i;
-	QPen qp;
-	QPainter paint(widget);
-
-	qp.setColor(SwapRB(color));
-	qp.setWidth(1);
-	qp.setStyle(Qt::SolidLine);
-	paint.setPen(qp);
-	paint.moveTo(pts[0].x, pts[0].y);
-	for (i = 1; i < cp; i++) paint.lineTo(pts[i].x, pts[i].y);
-	paint.flush();
-}
-
-void
-OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
-{
-	int i;
-	QPen qp;
-	QPainter paint(widget);
-
-	qp.setColor(SwapRB(color));
-	qp.setWidth(1);
-	qp.setStyle(Qt::SolidLine);
-	paint.setPen(qp);
-	paint.drawArc(p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, 0, 5760);
-	paint.flush();
-}
-
-bool
-OutputQT::SetMenu(int type)
-{
-	if(type == MENU_SPREAD){
-		QPopupMenu *file = new QPopupMenu(widget);
-		file->insertItem("&Open", widget, SLOT(cmOpen()));
+	bitBlt(widget, x1, y1, mempic, x1, y1,
+		x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP);
+	return true;
+}
+
+void
+OutputQT::ShowBitmap(int x, int y, anyOutput* src)
+{
+	BitMapQT *sr;
+	RECT *rc;
+
+	if(!widget || !mempic || !src)return;
+	sr = (BitMapQT*) src;		rc = &sr->DeskRect;
+	bitBlt(widget, x, y, sr->mempic, 0, 0, abs(rc->right-rc->left), 
+		abs(rc->bottom-rc->top), Qt::CopyROP);
+}
+
+void
+OutputQT::ShowLine(POINT * pts, int cp, DWORD color)
+{
+	int i;
+	QPen qp;
+	QPainter paint(widget);
+
+	qp.setColor(SwapRB(color));
+	qp.setWidth(1);
+	qp.setStyle(Qt::SolidLine);
+	qp.setCapStyle(Qt::RoundCap);
+	qp.setJoinStyle(Qt::RoundJoin);
+	paint.setPen(qp);
+	paint.moveTo(pts[0].x, pts[0].y);
+	for (i = 1; i < cp; i++) paint.lineTo(pts[i].x, pts[i].y);
+	paint.flush();
+}
+
+void
+OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
+{
+	int i;
+	QPen qp;
+	QPainter paint(widget);
+
+	qp.setColor(SwapRB(color));
+	qp.setWidth(1);
+	qp.setStyle(Qt::SolidLine);
+	qp.setCapStyle(Qt::RoundCap);
+	qp.setJoinStyle(Qt::RoundJoin);
+	paint.setPen(qp);
+	paint.drawArc(p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, 0, 5760);
+	paint.flush();
+}
+
+bool
+OutputQT::SetMenu(int type)
+{
+	if(type == MENU_SPREAD){
+		QPopupMenu *file = new QPopupMenu(widget);
+		file->insertItem("&Open", widget, SLOT(cmOpen()));
 		file->insertItem("&Save", widget, SLOT(cmSaveData()));
-		file->insertItem("Save &as", widget, SLOT(cmSaveDataAs()));
-		file->insertSeparator();
-		file->insertItem("&Print", widget, SLOT(cmPrint()));
-		file->insertSeparator();
-		file->insertItem("E&xit", widget, SLOT(cmExitRLP()));
-		file->insertSeparator();
-		file->insertItem("n.a.", widget, SLOT(cmFile1()), 0, CM_FILE1);
-		file->insertItem("n.a.", widget, SLOT(cmFile2()), 0, CM_FILE2);
-		file->insertItem("n.a.", widget, SLOT(cmFile3()), 0, CM_FILE3);
-		file->insertItem("n.a.", widget, SLOT(cmFile4()), 0, CM_FILE4);
-		file->insertItem("n.a.", widget, SLOT(cmFile5()), 0, CM_FILE5);
-		file->insertItem("n.a.", widget, SLOT(cmFile6()), 0, CM_FILE6);
+		file->insertItem("Save &as", widget, SLOT(cmSaveDataAs()));
+		file->insertSeparator();
+		file->insertItem("&Print", widget, SLOT(cmPrint()));
+		file->insertSeparator();
+		file->insertItem("E&xit", widget, SLOT(cmExitRLP()));
+		file->insertSeparator();
+		file->insertItem("n.a.", widget, SLOT(cmFile1()), 0, CM_FILE1);
+		file->insertItem("n.a.", widget, SLOT(cmFile2()), 0, CM_FILE2);
+		file->insertItem("n.a.", widget, SLOT(cmFile3()), 0, CM_FILE3);
+		file->insertItem("n.a.", widget, SLOT(cmFile4()), 0, CM_FILE4);
+		file->insertItem("n.a.", widget, SLOT(cmFile5()), 0, CM_FILE5);
+		file->insertItem("n.a.", widget, SLOT(cmFile6()), 0, CM_FILE6);
 
 		QPopupMenu *insert = new QPopupMenu(widget);
 		insert->insertItem("&Rows", widget, SLOT(cmInsRow()));
 		insert->insertItem("&Columns", widget, SLOT(cmInsCol()));
-
+
 		QPopupMenu *Delete = new QPopupMenu(widget);
 		Delete->insertItem("&Rows", widget, SLOT(cmDelRow()));
 		Delete->insertItem("&Columns", widget, SLOT(cmDelCol()));
 
-		QPopupMenu *edit = new QPopupMenu(widget);
+		QPopupMenu *edit = new QPopupMenu(widget);
 		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
 		edit->insertSeparator();
-		edit->insertItem("&Rows/Cols", widget, SLOT(cmAddRowCol()));
+		edit->insertItem("&Rows/Cols", widget, SLOT(cmAddRowCol()));
 		edit->insertItem("&Insert", insert);
 		edit->insertItem("&Delete", Delete);
-		edit->insertSeparator();
-		edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C);
-		edit->insertItem("C&ut", widget, SLOT(cmCut()), Qt::CTRL + Qt::Key_X);
-		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
-		edit->insertSeparator();
-		edit->insertItem("&Fill Range", widget, SLOT(cmFillRange()));
-
-		QPopupMenu *graph = new QPopupMenu(widget);
-		graph->insertItem("Create &Graph", widget, SLOT(cmNewGraph()));
-		graph->insertItem("Create &Page", widget, SLOT(cmNewPage()));
-		graph->insertItem("&Flush Graph(s)", widget, SLOT(cmDelGraph()));
-		graph->insertSeparator();
-		graph->insertItem("&Settings", widget, SLOT(cmDefaults()));
+		edit->insertSeparator();
+		edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C);
+		edit->insertItem("C&ut", widget, SLOT(cmCut()), Qt::CTRL + Qt::Key_X);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+		edit->insertSeparator();
+		edit->insertItem("&Fill Range", widget, SLOT(cmFillRange()));
+
+		QPopupMenu *graph = new QPopupMenu(widget);
+		graph->insertItem("Create &Graph", widget, SLOT(cmNewGraph()));
+		graph->insertItem("Create &Page", widget, SLOT(cmNewPage()));
+		graph->insertItem("&Flush Graph(s)", widget, SLOT(cmDelGraph()));
+		graph->insertSeparator();
+		graph->insertItem("&Settings", widget, SLOT(cmDefaults()));
 
 		QPopupMenu *stats = new QPopupMenu(widget);
+		stats->insertItem("&Comp. Means", widget, SLOT(cmRepCmeans()));
 		stats->insertItem("&Anova", widget, SLOT(cmRepanov()));
 		stats->insertItem("&Regression", widget, SLOT(cmRepregr()));
-
-		QPopupMenu *about = new QPopupMenu(widget);
-		about->insertItem("&About ...", widget, SLOT(cmAbout()));
-
-		menu = new QMenuBar(widget);
+		stats->insertItem("&2x2 Table", widget, SLOT(cmReptwoway()));
+
+		QPopupMenu *about = new QPopupMenu(widget);
+		about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+		menu = new QMenuBar(widget);
 		menu->insertItem("&File", file);			menu->insertItem("&Edit", edit);
 		menu->insertItem("&Statistics", stats);		menu->insertItem("&Graph", graph);
-		menu->insertItem("&?", about);
-#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
-		menu->setItemVisible(CM_FILE1, false);		menu->setItemVisible(CM_FILE2, false);
-		menu->setItemVisible(CM_FILE3, false);		menu->setItemVisible(CM_FILE4, false);
-		menu->setItemVisible(CM_FILE5, false);		menu->setItemVisible(CM_FILE6, false);
-#endif
-		}
-	else if(type == MENU_GRAPH) {
-		QPopupMenu *file = new QPopupMenu(widget);
-		file->insertItem("&Open", widget, SLOT(cmOpen()));
-		file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
-		file->insertItem("&Copy", widget, SLOT(cmCopyGraph()));
-		file->insertSeparator();
-		file->insertItem("&Print", widget, SLOT(cmPrint()));
-		file->insertItem("&Export", widget, SLOT(cmExport()));
-		file->insertSeparator();
-		file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
-
-		QPopupMenu *edit = new QPopupMenu(widget);
-		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
-		edit->insertSeparator();
-		edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
-		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
-		edit->insertSeparator();
-		edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
-		edit->insertSeparator();
-		edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
-
-		QPopupMenu *zoom = new QPopupMenu(widget);
-		zoom->insertTearOffHandle();
-		zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
-		zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
-		zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
-		zoom->insertSeparator();
-		zoom->insertItem("25%", widget, SLOT(cmZoom25()));
-		zoom->insertItem("50%", widget, SLOT(cmZoom50()));
-		zoom->insertItem("100%", widget, SLOT(cmZoom100()));
-		zoom->insertItem("200%", widget, SLOT(cmZoom200()));
-		zoom->insertItem("400%", widget, SLOT(cmZoom400()));
-
-		QPopupMenu *displ = new QPopupMenu(widget);
-		displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
-		displ->insertItem("&Zoom", zoom);
+		menu->insertItem("&?", about);
+#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
+		menu->setItemVisible(CM_FILE1, false);		menu->setItemVisible(CM_FILE2, false);
+		menu->setItemVisible(CM_FILE3, false);		menu->setItemVisible(CM_FILE4, false);
+		menu->setItemVisible(CM_FILE5, false);		menu->setItemVisible(CM_FILE6, false);
+#endif
+		}
+	else if(type == MENU_GRAPH) {
+		QPopupMenu *file = new QPopupMenu(widget);
+		file->insertItem("&Open", widget, SLOT(cmOpen()));
+		file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
+		file->insertItem("&Copy", widget, SLOT(cmCopyGraph()));
+		file->insertSeparator();
+		file->insertItem("&Print", widget, SLOT(cmPrint()));
+		file->insertItem("&Export", widget, SLOT(cmExport()));
+		file->insertSeparator();
+		file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
+
+		QPopupMenu *edit = new QPopupMenu(widget);
+		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+		edit->insertSeparator();
+		edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+		edit->insertSeparator();
+		edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
+		edit->insertSeparator();
+		edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
+
+		QPopupMenu *zoom = new QPopupMenu(widget);
+		zoom->insertTearOffHandle();
+		zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
+		zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
+		zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
+		zoom->insertSeparator();
+		zoom->insertItem("25%", widget, SLOT(cmZoom25()));
+		zoom->insertItem("50%", widget, SLOT(cmZoom50()));
+		zoom->insertItem("100%", widget, SLOT(cmZoom100()));
+		zoom->insertItem("200%", widget, SLOT(cmZoom200()));
+		zoom->insertItem("400%", widget, SLOT(cmZoom400()));
+
+		QPopupMenu *displ = new QPopupMenu(widget);
+		displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
+		displ->insertItem("&Zoom", zoom);
 		displ->insertItem("&Layers", widget, SLOT(cmLayers()));
-
-		QPopupMenu *tools = new QPopupMenu(widget);
-		tools->insertTearOffHandle();
-		tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
-		tools->insertSeparator();
-		tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
-		tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
-		tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
-		tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
-		tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
-		tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
-		tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
-		tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
-		tools->setCheckable(true);
-
-		QPopupMenu *plots = new QPopupMenu(widget);
-		plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
-		plots->insertItem("Add &Axis", widget, SLOT(cmAddAxis()));
-		plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
-		plots->insertSeparator();
-		plots->insertItem("&Configure", widget, SLOT(cmDefaults()));
-
-		QPopupMenu *about = new QPopupMenu(widget);
-		about->insertItem("&About ...", widget, SLOT(cmAbout()));
-
-		menu = new QMenuBar(widget);
-		menu->insertItem("&File", file);
-		menu->insertItem("&Edit", edit);
-		menu->insertItem("&Display", displ);
-		menu->insertItem("&Tools", tools);
-		menu->insertItem("&Plots", plots);
-		menu->insertItem("&?", about);
-		}
-	else if(type == MENU_PAGE) {
-		QPopupMenu *file = new QPopupMenu(widget);
-		file->insertItem("&Open", widget, SLOT(cmOpen()));
-		file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
-		file->insertSeparator();
-		file->insertItem("&Print", widget, SLOT(cmPrint()));
-		file->insertItem("&Export", widget, SLOT(cmExport()));
-		file->insertSeparator();
-		file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
-
-		QPopupMenu *edit = new QPopupMenu(widget);
-		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
-		edit->insertSeparator();
-		edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
-		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
-		edit->insertSeparator();
-		edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
-		edit->insertSeparator();
-		edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
-
-		QPopupMenu *zoom = new QPopupMenu(widget);
-		zoom->insertTearOffHandle();
-		zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
-		zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
-		zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
-		zoom->insertSeparator();
-		zoom->insertItem("25%", widget, SLOT(cmZoom25()));
-		zoom->insertItem("50%", widget, SLOT(cmZoom50()));
-		zoom->insertItem("100%", widget, SLOT(cmZoom100()));
-		zoom->insertItem("200%", widget, SLOT(cmZoom200()));
-		zoom->insertItem("400%", widget, SLOT(cmZoom400()));
-
-		QPopupMenu *displ = new QPopupMenu(widget);
-		displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
+
+		QPopupMenu *tools = new QPopupMenu(widget);
+		tools->insertTearOffHandle();
+		tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
+		tools->insertSeparator();
+		tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
+		tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
+		tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
+		tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
+		tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
+		tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
+		tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
+		tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
+		tools->setCheckable(true);
+
+		QPopupMenu *plots = new QPopupMenu(widget);
+		plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
+		plots->insertItem("Add &Axis", widget, SLOT(cmAddAxis()));
+		plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
+		plots->insertSeparator();
+		plots->insertItem("&Configure", widget, SLOT(cmDefaults()));
+
+		QPopupMenu *about = new QPopupMenu(widget);
+		about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+		menu = new QMenuBar(widget);
+		menu->insertItem("&File", file);
+		menu->insertItem("&Edit", edit);
+		menu->insertItem("&Display", displ);
+		menu->insertItem("&Tools", tools);
+		menu->insertItem("&Plots", plots);
+		menu->insertItem("&?", about);
+		}
+	else if(type == MENU_PAGE) {
+		QPopupMenu *file = new QPopupMenu(widget);
+		file->insertItem("&Open", widget, SLOT(cmOpen()));
+		file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
+		file->insertSeparator();
+		file->insertItem("&Print", widget, SLOT(cmPrint()));
+		file->insertItem("&Export", widget, SLOT(cmExport()));
+		file->insertSeparator();
+		file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
+
+		QPopupMenu *edit = new QPopupMenu(widget);
+		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+		edit->insertSeparator();
+		edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+		edit->insertSeparator();
+		edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
+		edit->insertSeparator();
+		edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
+
+		QPopupMenu *zoom = new QPopupMenu(widget);
+		zoom->insertTearOffHandle();
+		zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
+		zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
+		zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
+		zoom->insertSeparator();
+		zoom->insertItem("25%", widget, SLOT(cmZoom25()));
+		zoom->insertItem("50%", widget, SLOT(cmZoom50()));
+		zoom->insertItem("100%", widget, SLOT(cmZoom100()));
+		zoom->insertItem("200%", widget, SLOT(cmZoom200()));
+		zoom->insertItem("400%", widget, SLOT(cmZoom400()));
+
+		QPopupMenu *displ = new QPopupMenu(widget);
+		displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
 		displ->insertItem("&Zoom", zoom);
-		displ->insertItem("&Layers", widget, SLOT(cmLayers()));
-
-		QPopupMenu *tools = new QPopupMenu(widget);
-		tools->insertTearOffHandle();
-		tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
-		tools->insertSeparator();
-		tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
-		tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
-		tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
-		tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
-		tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
-		tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
-		tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
-		tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
-		tools->setCheckable(true);
-
-		QPopupMenu *plots = new QPopupMenu(widget);
-		plots->insertItem("Add &Graph", widget, SLOT(cmNewGraph()));
-		plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
+		displ->insertItem("&Layers", widget, SLOT(cmLayers()));
+
+		QPopupMenu *tools = new QPopupMenu(widget);
+		tools->insertTearOffHandle();
+		tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
+		tools->insertSeparator();
+		tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
+		tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
+		tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
+		tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
+		tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
+		tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
+		tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
+		tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
+		tools->setCheckable(true);
+
+		QPopupMenu *plots = new QPopupMenu(widget);
+		plots->insertItem("Add &Graph", widget, SLOT(cmNewGraph()));
+		plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
 		plots->insertItem("Add &Axis", widget, SLOT(cmAddAxis()));
-		plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
-		plots->insertSeparator();
-		plots->insertItem("Page &Settings", widget, SLOT(cmDefaults()));
-
-		QPopupMenu *about = new QPopupMenu(widget);
-		about->insertItem("&About ...", widget, SLOT(cmAbout()));
-
-		menu = new QMenuBar(widget);
-		menu->insertItem("&File", file);
-		menu->insertItem("&Edit", edit);
-		menu->insertItem("&Display", displ);
-		menu->insertItem("&Tools", tools);
-		menu->insertItem("&Plots", plots);
-		menu->insertItem("&?", about);
-		}
-	else return false;
-	menu->show();
-	MenuHeight = menu->height();
-	widget->resize(widget->width()+8, widget->height()+8);
-	return true;
-}
-
-void
-OutputQT::CheckMenu(int mid, bool check)
-{
-	if(mid < CM_T_STANDARD) switch(mid){					//tool mode identifier
-	case TM_STANDARD:	mid = CM_T_STANDARD;	break;
-	case TM_DRAW:		mid = CM_T_DRAW;		break;
-	case TM_POLYLINE:	mid = CM_T_POLYLINE;	break;
-	case TM_POLYGON:	mid = CM_T_POLYGON;		break;
-	case TM_RECTANGLE:	mid = CM_T_RECTANGLE;	break;
-	case TM_ROUNDREC:	mid = CM_T_ROUNDREC;	break;
-	case TM_ELLIPSE:	mid = CM_T_ELLIPSE;		break;
-	case TM_ARROW:		mid = CM_T_ARROW;		break;
-	case TM_TEXT:		mid = CM_T_TEXT;		break;
-	default:	return;
-		}
-	if(menu) menu->setItemChecked(mid, check);
-}
-
-void
-OutputQT::FileHistory()
-{
-	char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6};
-	int i, j, k;
-
-	if(!hasHistMenu || !defs.File1 || !menu) return;
-    for(i = 0; i < 6 && *history[i]; i++) {
-		k = strlen(*history[i]);
-		for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++);
-		if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++;
-		menu->changeItem(CM_FILE1+i, *history[i]+j);
-#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
-		menu->setItemVisible(CM_FILE1+i, true);
-#endif
-		}
-	HistMenuSize = i;
-}
-
-void
-OutputQT::CreateNewWindow(GraphObj *g)
-{
-	int w, h;
-
-	GetDesktopSize(&w, &h);
-	if(widget = new RLPwidget(0, 0, this, g)) {
-		widget->setCaption("OutputQT::CreateNewWindow");
-		widget->setGeometry(0, 0, (int)(w*.7f), (int)(h*.7f));
-		HScroll = ((RLPwidget*)widget)->HScroll;
-		VScroll = ((RLPwidget*)widget)->VScroll;
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Common widget support
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
-	: QWidget(par, name)
-{
-	int w, h;
-
-	GetDesktopSize(&w, &h);
-	mempic = new QPixmap(w, h);
-	parent = par;
-	OutputClass = o;
-	BaseObj = g;
-	setMinimumSize(100, 80);
-	setBackgroundMode(NoBackground);
-	HScroll = new QScrollBar(QScrollBar::Horizontal, this, 0);
-	HScroll->setRange(0, 1000);
-	HScroll->setSteps(1, 16);
-	connect(HScroll, SIGNAL(valueChanged(int)), SLOT(hScrollEvent(int)));
-	VScroll = new QScrollBar(QScrollBar::Vertical, this, 0);
-	VScroll->setRange(0, 1000);
-	VScroll->setSteps(1, 16);
-	connect(VScroll, SIGNAL(valueChanged(int)), SLOT(vScrollEvent(int)));
-	if(!MainWidget) QAppl->setMainWidget(MainWidget = this);
-	setMouseTracking(true);
-	setFocusPolicy(StrongFocus);
-}
-
-RLPwidget::~RLPwidget()
-{
-	if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
-	OutputClass = 0L;	BaseObj = 0L;
-}
-
-//public slots: menu items, events
-void
-RLPwidget::hScrollEvent(int pos)
-{
-	if(BaseObj){
-		BaseObj->Command(CMD_SETHPOS, (void*)(&pos), OutputClass);
-		repaint();
-		}
-}
-
-void
-RLPwidget::vScrollEvent(int pos)
-{
-	if(BaseObj){
-		BaseObj->Command(CMD_SETVPOS, (void*)(&pos), OutputClass);
-		repaint();
-		}
-}
-
-
-void
-RLPwidget::cmOpen()
-{
-	if(BaseObj)BaseObj->Command(CMD_OPEN, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmSaveData()
-{
-	if(BaseObj)BaseObj->Command(CMD_SAVEDATA, (void *)NULL, OutputClass);
-}
+		plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
+		plots->insertSeparator();
+		plots->insertItem("Page &Settings", widget, SLOT(cmDefaults()));
 
-void
-RLPwidget::cmSaveDataAs()
-{
-	if(BaseObj)BaseObj->Command(CMD_SAVEDATAAS, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmExit()
-{
-	if(BaseObj && BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){
-		if(BaseObj->parent) BaseObj->parent->Command(CMD_DELOBJ, BaseObj, 0L);
+		QPopupMenu *about = new QPopupMenu(widget);
+		about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+		menu = new QMenuBar(widget);
+		menu->insertItem("&File", file);
+		menu->insertItem("&Edit", edit);
+		menu->insertItem("&Display", displ);
+		menu->insertItem("&Tools", tools);
+		menu->insertItem("&Plots", plots);
+		menu->insertItem("&?", about);
 		}
-}
+	else return false;
+	menu->show();
+	MenuHeight = menu->height();
+	widget->resize(widget->width()+8, widget->height()+8);
+	return true;
+}
+
+void
+OutputQT::CheckMenu(int mid, bool check)
+{
+	if(mid < CM_T_STANDARD) switch(mid){					//tool mode identifier
+	case TM_STANDARD:	mid = CM_T_STANDARD;	break;
+	case TM_DRAW:		mid = CM_T_DRAW;		break;
+	case TM_POLYLINE:	mid = CM_T_POLYLINE;	break;
+	case TM_POLYGON:	mid = CM_T_POLYGON;		break;
+	case TM_RECTANGLE:	mid = CM_T_RECTANGLE;	break;
+	case TM_ROUNDREC:	mid = CM_T_ROUNDREC;	break;
+	case TM_ELLIPSE:	mid = CM_T_ELLIPSE;		break;
+	case TM_ARROW:		mid = CM_T_ARROW;		break;
+	case TM_TEXT:		mid = CM_T_TEXT;		break;
+	default:	return;
+		}
+	if(menu) menu->setItemChecked(mid, check);
+}
+
+void
+OutputQT::FileHistory()
+{
+	char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6};
+	int i, j, k;
+
+	if(!hasHistMenu || !defs.File1 || !menu) return;
+    for(i = 0; i < 6 && *history[i]; i++) {
+		k = strlen(*history[i]);
+		for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++);
+		if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++;
+		menu->changeItem(CM_FILE1+i, *history[i]+j);
+#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
+		menu->setItemVisible(CM_FILE1+i, true);
+#endif
+		}
+	HistMenuSize = i;
+}
+
+void
+OutputQT::CreateNewWindow(GraphObj *g)
+{
+	int w, h;
+
+	GetDesktopSize(&w, &h);
+	if(widget = new RLPwidget(0, 0, this, g)) {
+		widget->setCaption("OutputQT::CreateNewWindow");
+		widget->setGeometry(0, 0, (int)(w*.7f), (int)(h*.7f));
+		HScroll = ((RLPwidget*)widget)->HScroll;
+		VScroll = ((RLPwidget*)widget)->VScroll;
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common widget support
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
+	: QWidget(par, name)
+{
+	int w, h;
+
+	GetDesktopSize(&w, &h);
+	mempic = new QPixmap(w, h);
+	parent = par;
+	OutputClass = o;
+	BaseObj = g;
+	setMinimumSize(100, 80);
+	setBackgroundMode(NoBackground);
+	HScroll = new QScrollBar(QScrollBar::Horizontal, this, 0);
+	HScroll->setRange(0, 1000);
+	HScroll->setSteps(1, 16);
+	connect(HScroll, SIGNAL(valueChanged(int)), SLOT(hScrollEvent(int)));
+	VScroll = new QScrollBar(QScrollBar::Vertical, this, 0);
+	VScroll->setRange(0, 1000);
+	VScroll->setSteps(1, 16);
+	connect(VScroll, SIGNAL(valueChanged(int)), SLOT(vScrollEvent(int)));
+	if(!MainWidget) QAppl->setMainWidget(MainWidget = this);
+	setMouseTracking(true);
+	setFocusPolicy(StrongFocus);
+}
+
+RLPwidget::~RLPwidget()
+{
+	if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
+	OutputClass = 0L;	BaseObj = 0L;
+}
+
+//public slots: menu items, events
+void
+RLPwidget::hScrollEvent(int pos)
+{
+	if(BaseObj){
+		BaseObj->Command(CMD_SETHPOS, (void*)(&pos), OutputClass);
+		repaint();
+		}
+}
+
+void
+RLPwidget::vScrollEvent(int pos)
+{
+	if(BaseObj){
+		BaseObj->Command(CMD_SETVPOS, (void*)(&pos), OutputClass);
+		repaint();
+		}
+}
+
+
+void
+RLPwidget::cmOpen()
+{
+	if(BaseObj)BaseObj->Command(CMD_OPEN, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmSaveData()
+{
+	if(BaseObj)BaseObj->Command(CMD_SAVEDATA, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmSaveDataAs()
+{
+	if(BaseObj)BaseObj->Command(CMD_SAVEDATAAS, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmExit()
+{
+	if(BaseObj && BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){
+		if(BaseObj->parent) BaseObj->parent->Command(CMD_DELOBJ, BaseObj, 0L);
+		}
+}
 
 void
 RLPwidget::cmExitRLP()
@@ -2075,227 +2100,233 @@ RLPwidget::cmExitRLP()
 		}
 	QAppl->exit(0);
 }
-
-void
-RLPwidget::cmNewGraph()
-{
-	if(BaseObj)BaseObj->Command(CMD_NEWGRAPH, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmNewPage()
-{
-	if(BaseObj)BaseObj->Command(CMD_NEWPAGE, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmDelGraph()
-{
-	if(BaseObj)BaseObj->Command(CMD_DELGRAPH, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmAddPlot()
-{
-	if(BaseObj)BaseObj->Command(CMD_ADDPLOT, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmAddLegend()
-{
-	if(BaseObj)BaseObj->Command(CMD_LEGEND, (void *)NULL, OutputClass);
+
+void
+RLPwidget::cmNewGraph()
+{
+	if(BaseObj)BaseObj->Command(CMD_NEWGRAPH, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmNewPage()
+{
+	if(BaseObj)BaseObj->Command(CMD_NEWPAGE, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmDelGraph()
+{
+	if(BaseObj)BaseObj->Command(CMD_DELGRAPH, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmAddPlot()
+{
+	if(BaseObj)BaseObj->Command(CMD_ADDPLOT, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmAddLegend()
+{
+	if(BaseObj)BaseObj->Command(CMD_LEGEND, (void *)NULL, OutputClass);
 }
 
 void
 RLPwidget::cmLayers()
 {
 	if(BaseObj)BaseObj->Command(CMD_LAYERS, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmAbout()
-{
-	RLPlotInfo();
-}
-
-void
-RLPwidget::cmAddRowCol()
-{
-	if(BaseObj)BaseObj->Command(CMD_ADDROWCOL, (void *)NULL, OutputClass);
-}
-
-void
-RLPwidget::cmCopy()
-{
-	if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
-		if(BaseObj->Command(CMD_QUERY_COPY, 0L, OutputClass))
-			CopyData(BaseObj);
-		}
-}
-
-void
-RLPwidget::cmCut()
-{
-	if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
-		BaseObj->Command(CMD_CUT, 0L, OutputClass);
-		CopyData(BaseObj);
-		}
-}
-
-void
-RLPwidget::cmPaste()
-{
-	if(BaseObj) {
-		OutputClass->MouseCursor(MC_WAIT, true);
-		TestClipboard(BaseObj);
-		BaseObj->Command(CMD_MOUSECURSOR, 0L, OutputClass);
-		}
-}
-
-void
-RLPwidget::cmCopyGraph()
-{
-	if(BaseObj) CopyGraph(BaseObj);
-}
-
-void
-RLPwidget::cmSaveGraphAs()
-{
-	SaveGraphAs(BaseObj);
-}
-
-void
-RLPwidget::cmRedraw()
-{
-	if(OutputClass && BaseObj && OutputClass->Erase(defs.Color(COL_BG))) {
-		BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
-		repaint();
-		}
-}
-
-void
-RLPwidget::cmZoom25()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"25"), OutputClass);
-}
-
-void
-RLPwidget::cmZoom50()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"50"), OutputClass);
-}
-
-void
-RLPwidget::cmZoom100()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"100"), OutputClass);
-}
-
-void
-RLPwidget::cmZoom200()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"200"), OutputClass);
-}
-
-void
-RLPwidget::cmZoom400()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"400"), OutputClass);
-}
-
-void
-RLPwidget::cmZoomIn()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"+"), OutputClass);
-}
-
-void
-RLPwidget::cmZoomOut()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"-"), OutputClass);
-}
-
-void
-RLPwidget::cmZoomFit()
-{
-	BaseObj->Command(CMD_ZOOM, (void*)(&"fit"), OutputClass);
-}
-
-void
-RLPwidget::cmPrint()
-{
-	int m;
-	PrintQT out(0L, 0L);
-
-	if(!BaseObj) return;
-	if(BaseObj->Id == GO_SPREADDATA) {
-		m = iround(out.hres/60.0);
-#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
-		out.printer->setMargins(m, m, m, m);
-#endif
-		BaseObj->Command(CMD_PRINT, 0L, &out);
-		}
-	else if(out.StartPage()){
-		BaseObj->DoPlot(&out);
-		out.EndPage();
-		}
-	BaseObj->DoPlot(OutputClass);
-}
-
-void
-RLPwidget::cmExport()
-{
-	OpenExportName(BaseObj, 0L);
-	BaseObj->DoPlot(0L);
-}
-
-void
-RLPwidget::cmDelObj()
-{
-	if(CurrGO && CurrGO->parent && CurrGO->parent->
-		Command(CMD_DELOBJ, (void*)CurrGO, OutputClass)) {
-		CurrGO = 0L;
-		OutputClass->Erase(defs.Color(COL_BG));
-		BaseObj->DoPlot(OutputClass);
-		}
-	else if(!CurrGO) InfoBox("No object selected!");
-}
-
-void
-RLPwidget::cmUpdate()
-{
-	if(BaseObj) BaseObj->Command(CMD_UPDATE, 0L, OutputClass);
-}
-
-void
-RLPwidget::cmDefaults()
-{
-	BaseObj->Command(CMD_CONFIG, 0L, OutputClass);
-}
-
-void
-RLPwidget::cmAddAxis()
-{
-	BaseObj->Command(CMD_ADDAXIS, 0L, OutputClass);
-}
-
-void
-RLPwidget::cmUndo()
-{
-	BaseObj->Command(CMD_UNDO, 0L, OutputClass);
-}
-
-void
-RLPwidget::cmFillRange()
-{
-	BaseObj->Command(CMD_FILLRANGE, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmAbout()
+{
+	RLPlotInfo();
+}
+
+void
+RLPwidget::cmAddRowCol()
+{
+	if(BaseObj)BaseObj->Command(CMD_ADDROWCOL, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmCopy()
+{
+	if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
+		if(BaseObj->Command(CMD_QUERY_COPY, 0L, OutputClass))
+			CopyData(BaseObj);
+		}
+}
+
+void
+RLPwidget::cmCut()
+{
+	if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
+		BaseObj->Command(CMD_CUT, 0L, OutputClass);
+		CopyData(BaseObj);
+		}
+}
+
+void
+RLPwidget::cmPaste()
+{
+	if(BaseObj) {
+		OutputClass->MouseCursor(MC_WAIT, true);
+		if(BaseObj->Id == GO_SPREADDATA) TestClipboard(BaseObj);
+		else if(BaseObj->Id == GO_PAGE || BaseObj->Id == GO_GRAPH){
+			if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(CMD_PASTE, 0L, OutputClass));
+			else TestClipboard(BaseObj);
+			}
+		BaseObj->Command(CMD_MOUSECURSOR, 0L, OutputClass);
+		}
+}
+
+void
+RLPwidget::cmCopyGraph()
+{
+	EmptyClip();
+	if(CurrGO && CurrGO->Id == GO_TEXTFRAME) if(CurrGO->Command(CMD_COPY, 0L, OutputClass))return;
+	if(BaseObj) CopyGraph(BaseObj);
+}
+
+void
+RLPwidget::cmSaveGraphAs()
+{
+	SaveGraphAs(BaseObj);
+}
+
+void
+RLPwidget::cmRedraw()
+{
+	if(OutputClass && BaseObj && OutputClass->Erase(defs.Color(COL_BG))) {
+		BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
+		repaint();
+		}
+}
+
+void
+RLPwidget::cmZoom25()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"25"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom50()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"50"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom100()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"100"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom200()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"200"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom400()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"400"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomIn()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"+"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomOut()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"-"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomFit()
+{
+	BaseObj->Command(CMD_ZOOM, (void*)(&"fit"), OutputClass);
+}
+
+void
+RLPwidget::cmPrint()
+{
+	int m;
+	PrintQT out(0L, 0L);
+
+	if(!BaseObj) return;
+	if(BaseObj->Id == GO_SPREADDATA) {
+		m = iround(out.hres/60.0);
+#ifdef Q_CHECK_PTR				//Qt version 3, n.a. in version 2
+		out.printer->setMargins(m, m, m, m);
+#endif
+		BaseObj->Command(CMD_PRINT, 0L, &out);
+		}
+	else if(out.StartPage()){
+		BaseObj->DoPlot(&out);
+		out.EndPage();
+		}
+	BaseObj->DoPlot(OutputClass);
+}
+
+void
+RLPwidget::cmExport()
+{
+	OpenExportName(BaseObj, 0L);
+	BaseObj->DoPlot(0L);
+}
+
+void
+RLPwidget::cmDelObj()
+{
+	if(CurrGO && CurrGO->parent && CurrGO->parent->
+		Command(CMD_DELOBJ, (void*)CurrGO, OutputClass)) {
+		CurrGO = 0L;
+		OutputClass->Erase(defs.Color(COL_BG));
+		BaseObj->DoPlot(OutputClass);
+		}
+	else if(!CurrGO) InfoBox("No object selected!");
+}
+
+void
+RLPwidget::cmUpdate()
+{
+	if(BaseObj) BaseObj->Command(CMD_UPDATE, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmDefaults()
+{
+	BaseObj->Command(CMD_CONFIG, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmAddAxis()
+{
+	BaseObj->Command(CMD_ADDAXIS, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmUndo()
+{
+	BaseObj->Command(CMD_UNDO, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmFillRange()
+{
+	BaseObj->Command(CMD_FILLRANGE, 0L, OutputClass);
 }
 
 void
 RLPwidget::cmInsRow()
 {
 	BaseObj->Command(CMD_INSROW, 0L, OutputClass);
-}
+}
 
 void
 RLPwidget::cmInsCol()
@@ -2314,64 +2345,70 @@ RLPwidget::cmDelCol()
 {
 	BaseObj->Command(CMD_DELCOL, 0L, OutputClass);
 }
-
-void ToolMenu(GraphObj *b, anyOutput *o, int tm)
-{
-	if(b && o) b->Command(CMD_TOOLMODE, (void*)(& tm), o);
-}
-
-void
-RLPwidget::cmtStandard()
-{
-	ToolMenu(BaseObj, OutputClass, TM_STANDARD);
-}
-
-void
-RLPwidget::cmtDraw()
-{
-	ToolMenu(BaseObj, OutputClass, TM_DRAW);
-}
-
-void
-RLPwidget::cmtPolyline()
-{
-	ToolMenu(BaseObj, OutputClass, TM_POLYLINE);
-}
-
-void
-RLPwidget::cmtPolygon()
-{
-	ToolMenu(BaseObj, OutputClass, TM_POLYGON);
-}
-
-void
-RLPwidget::cmtRectangle()
-{
-	ToolMenu(BaseObj, OutputClass, TM_RECTANGLE);
-}
-
-void
-RLPwidget::cmtRoundrect()
-{
-	ToolMenu(BaseObj, OutputClass, TM_ROUNDREC);
-}
-
-void
-RLPwidget::cmtEllipse()
-{
-	ToolMenu(BaseObj, OutputClass, TM_ELLIPSE);
-}
-
-void
-RLPwidget::cmtArrow()
-{
-	ToolMenu(BaseObj, OutputClass, TM_ARROW);
-}
-
-void
-RLPwidget::cmtText()
-{
-	ToolMenu(BaseObj, OutputClass, TM_TEXT);
+
+void ToolMenu(GraphObj *b, anyOutput *o, int tm)
+{
+	if(b && o) b->Command(CMD_TOOLMODE, (void*)(& tm), o);
+}
+
+void
+RLPwidget::cmtStandard()
+{
+	ToolMenu(BaseObj, OutputClass, TM_STANDARD);
+}
+
+void
+RLPwidget::cmtDraw()
+{
+	ToolMenu(BaseObj, OutputClass, TM_DRAW);
+}
+
+void
+RLPwidget::cmtPolyline()
+{
+	ToolMenu(BaseObj, OutputClass, TM_POLYLINE);
+}
+
+void
+RLPwidget::cmtPolygon()
+{
+	ToolMenu(BaseObj, OutputClass, TM_POLYGON);
+}
+
+void
+RLPwidget::cmtRectangle()
+{
+	ToolMenu(BaseObj, OutputClass, TM_RECTANGLE);
+}
+
+void
+RLPwidget::cmtRoundrect()
+{
+	ToolMenu(BaseObj, OutputClass, TM_ROUNDREC);
+}
+
+void
+RLPwidget::cmtEllipse()
+{
+	ToolMenu(BaseObj, OutputClass, TM_ELLIPSE);
+}
+
+void
+RLPwidget::cmtArrow()
+{
+	ToolMenu(BaseObj, OutputClass, TM_ARROW);
+}
+
+void
+RLPwidget::cmtText()
+{
+	ToolMenu(BaseObj, OutputClass, TM_TEXT);
+}
+
+void
+RLPwidget::cmRepCmeans()
+{
+	if(BaseObj) rep_compmeans(BaseObj, BaseObj->data);
 }
 
 void
@@ -2379,678 +2416,706 @@ RLPwidget::cmRepanov()
 {
 	if(BaseObj) rep_anova(BaseObj, BaseObj->data);
 }
-
+
 void
 RLPwidget::cmRepregr()
 {
 	if(BaseObj) rep_regression(BaseObj, BaseObj->data);
 }
-
-//protected: widget events
-void
-RLPwidget::paintEvent(QPaintEvent *range)
-{
-	QRect rc;
-
-	rc = range->rect();
-	bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
-		1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
-}
-
-void
-RLPwidget::resizeEvent(QResizeEvent *)
-{
-	HScroll->resize(width() -16, 16);
-	HScroll->move(0, height()-16);
-	VScroll->resize(16, height()-OutputClass->MenuHeight-16);
-	VScroll->move(width()-16, OutputClass->MenuHeight);
-	if(BaseObj) BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
-}
-
-void
-RLPwidget::closeEvent(QCloseEvent *e)
-{
+
+void
+RLPwidget::cmReptwoway()
+{
+	if(BaseObj) rep_twowaytable(BaseObj, BaseObj->data);
+}
+
+//protected: widget events
+void
+RLPwidget::paintEvent(QPaintEvent *range)
+{
+	QRect rc;
+
+	rc = range->rect();
+	bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
+		1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
+}
+
+void
+RLPwidget::resizeEvent(QResizeEvent *)
+{
+	HScroll->resize(width() -16, 16);
+	HScroll->move(0, height()-16);
+	VScroll->resize(16, height()-OutputClass->MenuHeight-16);
+	VScroll->move(width()-16, OutputClass->MenuHeight);
+	if(BaseObj) BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
+}
+
+void
+RLPwidget::closeEvent(QCloseEvent *e)
+{
 	if(BaseObj){
 		if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)) {
 			if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
-			OutputClass = 0L;			BaseObj = 0L;
+			OutputClass = 0L;			BaseObj = 0L;
 			e->accept();
 			}
 		}
-	else e->accept();
-}
-
-void
-RLPwidget::mouseDoubleClickEvent(QMouseEvent *e)
-{
-	MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
-
-	if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-RLPwidget::mousePressEvent(QMouseEvent *e)
-{
-	int i;
-	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
-
-	HideTextCursor();
-	i = e->state();
+	else e->accept();
+}
+
+void
+RLPwidget::mouseDoubleClickEvent(QMouseEvent *e)
+{
+	MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
+
+	if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mousePressEvent(QMouseEvent *e)
+{
+	int i;
+	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
+
+	HideTextCursor();			i = e->state();
 	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
 	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
-	if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-RLPwidget::mouseReleaseEvent(QMouseEvent *e)
+	if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mouseReleaseEvent(QMouseEvent *e)
 {
 	int i;
-	MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP :
-		e->button() == Qt::RightButton ? MOUSE_RBUP : -1, e->x(), e->y()};
+	MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP :
+		e->button() == Qt::RightButton ? MOUSE_RBUP : -1, e->x(), e->y()};
 
 	i = e->state();
 	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
 	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
-	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-RLPwidget::mouseMoveEvent(QMouseEvent *e)
-{
-	int i;
-	MouseEvent mev = {0, MOUSE_MOVE, e->x(), e->y()};
-
+	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mouseMoveEvent(QMouseEvent *e)
+{
+	int i;
+	MouseEvent mev = {0, MOUSE_MOVE, e->x(), e->y()};
+
 	i = e->state();
 	if(i & Qt::LeftButton) mev.StateFlags |= 0x01;
 	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
 	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
-	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-RLPwidget::keyPressEvent(QKeyEvent *e)
-{
-	int i, c;
-
-	if(BaseObj) switch(c = e->key()) {
-		case Key_Prior:
+	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::keyPressEvent(QKeyEvent *e)
+{
+	int i, c;
+
+	if(BaseObj) switch(c = e->key()) {
+		case Key_Prior:
 			i = e->state();
 			if(i & Qt::ShiftButton) BaseObj->Command(CMD_SHPGUP, 0L, OutputClass);
-			else BaseObj->Command(CMD_PAGEUP, 0L, OutputClass);
-			break;
-		case Key_Next:
+			else BaseObj->Command(CMD_PAGEUP, 0L, OutputClass);
+			break;
+		case Key_Next:
 			i = e->state();
 			if(i & Qt::ShiftButton) BaseObj->Command(CMD_SHPGDOWN, 0L, OutputClass);
-			else BaseObj->Command(CMD_PAGEDOWN, 0L, OutputClass);
-			break;
-		case Key_Left:
-			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTLEFT, 0L, OutputClass);
-			else BaseObj->Command(CMD_CURRLEFT, 0L, OutputClass);
-			break;
-		case Key_Right:
-			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
-			else BaseObj->Command(CMD_CURRIGHT, 0L, OutputClass);
-			break;
-		case Key_Up:
-			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTUP, 0L, OutputClass);
-			else BaseObj->Command(CMD_CURRUP, 0L, OutputClass);
-			break;
-		case Key_Down:
-			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTDOWN, 0L, OutputClass);
-			else BaseObj->Command(CMD_CURRDOWN, 0L, OutputClass);
-			break;
-		case Key_Delete:
-			BaseObj->Command(CMD_DELETE, 0L, OutputClass);
-			break;
-		case Key_Tab:
-			BaseObj->Command(CMD_TAB, 0L, OutputClass);
-			break;
-		case Key_Backtab:
-			BaseObj->Command(CMD_SHTAB, 0L, OutputClass);
-			break;
-		case Key_Home:
-			BaseObj->Command(CMD_POS_FIRST, 0L, OutputClass);
-			break;
-		case Key_End:
-			BaseObj->Command(CMD_POS_LAST, 0L, OutputClass);
-			break;
-		default:
-			c = e->ascii();
-			if(c == 3) cmCopy();
-			else if(c == 22) cmPaste();
-			else if(c == 26) cmUndo();
-			else if(c >1 && c < 256)
-				BaseObj->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
-			break;
-		}
-	e->accept();
-}
-
-void
-RLPwidget::focusInEvent(QFocusEvent *e)
-{
-	CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
-	if(BaseObj) {
-		if(BaseObj->Id == GO_GRAPH) CurrGraph = (Graph*)BaseObj;
-		}
-}
-
-//private functions
-void
-RLPwidget::openHistoryFile(int idx)
-{
-	char *name = 0L;
-
-	switch (idx) {
-	case 0:			name = defs.File1;			break;
-	case 1:			name = defs.File2;			break;
-	case 2:			name = defs.File3;			break;
-	case 3:			name = defs.File4;			break;
-	case 4:			name = defs.File5;			break;
-	case 5:			name = defs.File6;			break;
-		}
-	if(name && FileExist(name)) {
-		BaseObj->Command(CMD_DROPFILE, name, OutputClass);
-		defs.FileHistory(name);
-		OutputClass->FileHistory();
-		}
-}
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Print and output EPS to file
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class FileEPS:public QPrinter {
-public:
-	FileEPS(GraphObj *g, anyOutput *o);
-
-protected:
-	int metric(int) const;
-
-private:
-	GraphObj *go;
-	anyOutput *out;
-};
-
-FileEPS::FileEPS(GraphObj *g, anyOutput *o)
-{
-	go = g;
-	out = o;
-}
-
-int
-FileEPS::metric(int m) const
-{
-	if(go && out)switch (m) {
-	case QPaintDeviceMetrics::PdmWidth:
-		return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
-	case QPaintDeviceMetrics::PdmHeight:
-		return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
-	case QPaintDeviceMetrics::PdmWidthMM:
-		return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) *
-			Units[defs.cUnits].convert);
-	case QPaintDeviceMetrics::PdmHeightMM:
-		return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) *
-			Units[defs.cUnits].convert);
-		}
-	return QPrinter::metric(m);
-}
-
-PrintQT::PrintQT(GraphObj *g, char *file)
-{
-	hres = vres = 720.0;
-	units = defs.cUnits;
-	Box1.Xmin = Box1.Ymin = 0.0;
-	Box1.Xmax = Box1.Ymax = 6000;
-	DeskRect.left = DeskRect.top = 0;
-	DeskRect.right = (long)(hres*6.0);
-	DeskRect.bottom = (long)(vres*8.0);
-	dxf.setMatrix(0.1, 0.0, 0.0, 0.1, 0.0, 0.0);
-	hgo = 0L;
-	if(file) fileName = strdup(file);
-	else fileName = 0L;
-	go = g;
-	if(fileName && go) printer = new FileEPS(g, this);
-	else printer = new QPrinter;
-	bPrinting = false;
-}
-
-PrintQT::~PrintQT()
-{
-	if(printer) delete(printer);
-	if(hgo) delete(hgo);
-	if(fileName) free(fileName);
-}
-
-bool 
-PrintQT::ActualSize(RECT *rc)
-{
-	if(printer) {
-		QPaintDeviceMetrics dm(printer);	rc->top = rc->left = 0;
-		rc->bottom = dm.height() *10;		rc->right = dm.width() *10;
-		return true;
-		}
-	return false;
-}
-
-bool
-PrintQT::SetLine(LineDEF *lDef)
-{
-	int iw;
-
-	if(lDef->width != LineWidth || lDef->width != LineWidth ||
-		lDef->pattern != dPattern || lDef->color != dLineCol) {
-		LineWidth = lDef->width;
-		iw = iround(un2fix(lDef->width));
-		dPattern = lDef->pattern;
-		RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
-		RLP.fp = 0.0;
-		if(iLine == iw && dLineCol == lDef->color) return true;
-		iLine = iw;
-		dLineCol = lDef->color;
-		qPen.setColor(SwapRB(dLineCol));
-		qPen.setWidth(iw);
-		qPen.setStyle(Qt::SolidLine);
-		qPen.setCapStyle(Qt::RoundCap);
-		qPen.setJoinStyle(Qt::RoundJoin);
-		qPainter.setPen(qPen);
-		}
-	return true;
-}
-
-bool
-PrintQT::SetFill(FillDEF *fill)
-{
-	if(!fill) return false;
-	if((fill->type & 0xff) != FILL_NONE) {
-		if(!hgo) hgo = new HatchOut(this);
-		if(hgo) hgo->SetFill(fill);
-		}
-	else {
-		if(hgo) delete hgo;
-		hgo = 0L;
-		}
-	qPainter.setBrush(QColor(SwapRB(fill->color)));
-	dFillCol = fill->color;
-	dFillCol2 = fill->color2;
-	return true;
-}
-
-bool
-PrintQT::SetTextSpec(TextDEF *set)
-{
+			else BaseObj->Command(CMD_PAGEDOWN, 0L, OutputClass);
+			break;
+		case Key_Left:
+			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRLEFT, 0L, OutputClass);
+			break;
+		case Key_Right:
+			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRIGHT, 0L, OutputClass);
+			break;
+		case Key_Up:
+			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTUP, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRUP, 0L, OutputClass);
+			break;
+		case Key_Down:
+			if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRDOWN, 0L, OutputClass);
+			break;
+		case Key_Delete:
+			BaseObj->Command(CMD_DELETE, 0L, OutputClass);
+			break;
+		case Key_Tab:
+			BaseObj->Command(CMD_TAB, 0L, OutputClass);
+			break;
+		case Key_Backtab:
+			BaseObj->Command(CMD_SHTAB, 0L, OutputClass);
+			break;
+		case Key_Home:
+			BaseObj->Command(CMD_POS_FIRST, 0L, OutputClass);
+			break;
+		case Key_End:
+			BaseObj->Command(CMD_POS_LAST, 0L, OutputClass);
+			break;
+		default:
+			c = e->ascii();
+			if(c == 3) cmCopy();
+			else if(c == 22) cmPaste();
+			else if(c == 26) cmUndo();
+			else if(c >1 && c < 256)
+				BaseObj->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
+			break;
+		}
+	e->accept();
+}
+
+void
+RLPwidget::focusInEvent(QFocusEvent *e)
+{
+	CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+	if(BaseObj) {
+		if(BaseObj->Id == GO_GRAPH) CurrGraph = (Graph*)BaseObj;
+		}
+}
+
+//private functions
+void
+RLPwidget::openHistoryFile(int idx)
+{
+	char *name = 0L;
+
+	switch (idx) {
+	case 0:			name = defs.File1;			break;
+	case 1:			name = defs.File2;			break;
+	case 2:			name = defs.File3;			break;
+	case 3:			name = defs.File4;			break;
+	case 4:			name = defs.File5;			break;
+	case 5:			name = defs.File6;			break;
+		}
+	if(name && FileExist(name)) {
+		BaseObj->Command(CMD_DROPFILE, name, OutputClass);
+		defs.FileHistory(name);
+		OutputClass->FileHistory();
+		}
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Print and output EPS to file
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class FileEPS:public QPrinter {
+public:
+	FileEPS(GraphObj *g, anyOutput *o);
+
+protected:
+	int metric(int) const;
+
+private:
+	GraphObj *go;
+	anyOutput *out;
+};
+
+FileEPS::FileEPS(GraphObj *g, anyOutput *o)
+{
+	go = g;
+	out = o;
+}
+
+int
+FileEPS::metric(int m) const
+{
+	if(go && out)switch (m) {
+	case QPaintDeviceMetrics::PdmWidth:
+		return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
+	case QPaintDeviceMetrics::PdmHeight:
+		return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
+	case QPaintDeviceMetrics::PdmWidthMM:
+		return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) *
+			Units[defs.cUnits].convert);
+	case QPaintDeviceMetrics::PdmHeightMM:
+		return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) *
+			Units[defs.cUnits].convert);
+		}
+	return QPrinter::metric(m);
+}
+
+PrintQT::PrintQT(GraphObj *g, char *file)
+{
+	units = defs.cUnits;
+	dxf.setMatrix(0.1, 0.0, 0.0, 0.1, 0.0, 0.0);
+	hgo = 0L;
+	if(file) fileName = strdup(file);
+	else fileName = 0L;
+	go = g;
+	if(fileName && go) printer = new FileEPS(g, this);
+	else printer = new QPrinter(QPrinter::HighResolution);
+	hres = vres = (9.5*((double)printer->resolution()));
+	Box1.Xmin = Box1.Ymin = 0.0;
+	Box1.Xmax = Box1.Ymax = 6000;
+	DeskRect.left = DeskRect.top = 0;
+	DeskRect.right = (long)(hres*6.0);
+	DeskRect.bottom = (long)(vres*8.0);
+	bPrinting = false;
+}
+
+PrintQT::~PrintQT()
+{
+	if(printer) delete(printer);
+	if(hgo) delete(hgo);
+	if(fileName) free(fileName);
+}
+
+bool 
+PrintQT::ActualSize(RECT *rc)
+{
+	if(printer) {
+		QPaintDeviceMetrics dm(printer);	rc->top = rc->left = 0;
+		rc->bottom = dm.height() *10;		rc->right = dm.width() *10;
+		return true;
+		}
+	return false;
+}
+
+bool
+PrintQT::SetLine(LineDEF *lDef)
+{
+	int iw;
+
+	if(lDef->width != LineWidth || lDef->width != LineWidth ||
+		lDef->pattern != dPattern || lDef->color != dLineCol) {
+		LineWidth = lDef->width;
+		iw = iround(un2fix(lDef->width));
+		dPattern = lDef->pattern;
+		RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+		RLP.fp = 0.0;
+		if(iLine == iw && dLineCol == lDef->color) return true;
+		iLine = iw;
+		dLineCol = lDef->color;
+		qPen.setColor(SwapRB(dLineCol));
+		qPen.setWidth(iw);
+		qPen.setStyle(Qt::SolidLine);
+		qPen.setCapStyle(Qt::RoundCap);
+		qPen.setJoinStyle(Qt::RoundJoin);
+		qPainter.setPen(qPen);
+		}
+	return true;
+}
+
+bool
+PrintQT::SetFill(FillDEF *fill)
+{
+	if(!fill) return false;
+	if((fill->type & 0xff) != FILL_NONE) {
+		if(!hgo) hgo = new HatchOut(this);
+		if(hgo) hgo->SetFill(fill);
+		}
+	else {
+		if(hgo) delete hgo;
+		hgo = 0L;
+		}
+	qPainter.setBrush(QColor(SwapRB(fill->color)));
+	dFillCol = fill->color;
+	dFillCol2 = fill->color2;
+	return true;
+}
+
+bool
+PrintQT::SetTextSpec(TextDEF *set)
+{
+	set->iSize = un2ix(set->fSize/7.5);
 	return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter);
-}
-
-bool
-PrintQT::StartPage()
-{
-	if(!printer || bPrinting) return false;
-	if(fileName) {
-		VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
-		VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
-		printer->setOutputFileName(fileName);
-		printer->setFullPage(true);
-		qPainter.begin(printer);
-		qPainter.setWorldMatrix(dxf, FALSE);
-		return bPrinting = true;
-		}
-
-	if(printer->setup(0)){
-		qPainter.begin(printer);
-		qPainter.setWorldMatrix(dxf, FALSE);
-		return bPrinting = true;
-		}
-	else return false;
-}
-
-bool
-PrintQT::EndPage()
-{
-	qPainter.flush();	qPainter.end();	bPrinting = false;
-	return true;
-}
-
-bool
-PrintQT::Eject()
-{
-	if(!bPrinting) return false;
-	qPainter.flush();	qPainter.end();		qPainter.begin(printer);
-	qPainter.setWorldMatrix(dxf, FALSE);
-	return true;
-}
-
-bool
-PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
-{
-	QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
-		text, cb > 0 ? cb : strlen(text));
-	*width = rc.rRight() - rc.rLeft();		*height = rc.rBottom() - rc.rTop();
-	return true;
-}
-
-bool
-PrintQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
-{
-	qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
-	if(hgo) return hgo->oCircle(x1, y1, x2, y2);
-	return true;
-}
-
-bool
-PrintQT::oPolyline(POINT * pts, int cp, char *nam)
-{
-	int i;
-
-	if(cp < 1) return false;
-	if (dPattern) {
-		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
-		}
-	else {
-		qPainter.moveTo(pts[0].x, pts[0].y);
-		for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
-		}
-	return true;
-}
-
-bool
-PrintQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
-{
-	qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
-	if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
-	return true;
-}
-
-bool
-PrintQT::oSolidLine(POINT *p)
-{
-	qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
-	return true;
-}
-
-bool
-PrintQT::oTextOut(int x, int y, char *txt, int cb)
+}
+
+bool
+PrintQT::StartPage()
+{
+	if(!printer || bPrinting) return false;
+	if(fileName) {
+		VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
+		VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
+		printer->setOutputFileName(fileName);
+		printer->setFullPage(true);
+		qPainter.begin(printer);
+		qPainter.setWorldMatrix(dxf, FALSE);
+		return bPrinting = true;
+		}
+	if(printer->setup(0)){
+		qPainter.begin(printer);
+		qPainter.setWorldMatrix(dxf, FALSE);
+		return bPrinting = true;
+		}
+	else return false;
+}
+
+bool
+PrintQT::EndPage()
+{
+	qPainter.flush();	qPainter.end();	bPrinting = false;
+	return true;
+}
+
+bool
+PrintQT::Eject()
+{
+	if(!bPrinting) return false;
+	qPainter.flush();	qPainter.end();		qPainter.begin(printer);
+	qPainter.setWorldMatrix(dxf, FALSE);
+	return true;
+}
+
+bool
+PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	if(!text || !text[0]){
+		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, "A", 1);
+		*width = rc.rLeft();
+		}
+	else {
+		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
+		text, cb > 0 ? cb : strlen(text));
+		*width = rc.rRight() - rc.rLeft();
+		}
+	*height = TxtSet.iSize +2;
+	return true;
+}
+
+bool
+PrintQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+	qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
+	if(hgo) return hgo->oCircle(x1, y1, x2, y2);
+	return true;
+}
+
+bool
+PrintQT::oPolyline(POINT * pts, int cp, char *nam)
 {
+	int i;
+
+	if(cp < 1) return false;
+	if (dPattern) {
+		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+		}
+	else {
+		qPainter.moveTo(pts[0].x, pts[0].y);
+		for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
+		}
+	return true;
+}
+
+bool
+PrintQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+	qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+	if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
+	return true;
+}
+
+bool
+PrintQT::oSolidLine(POINT *p)
+{
+	qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
+	return true;
+}
+
+bool
+PrintQT::oTextOut(int x, int y, char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	if(TxtSet.fSize > 0.0) TxtSet.iSize = un2ix(TxtSet.fSize);
+	if(!TxtSet.iSize) return false;
+	if(TxtSet.Align & TXA_VCENTER) y += iround(TxtSet.iSize * 0.4);
+	else if(TxtSet.Align & TXA_VBOTTOM) y -= iround(TxtSet.iSize * 0.1);
+	else y += iround(TxtSet.iSize * 1.0);
 	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
 }
-
-bool
-PrintQT::oPolygon(POINT *pts, int cp, char *nam)
-{
-	int i;
-
-	QPointArray *a;
-
-	if(!pts || cp <2) return false;
-	a = new QPointArray(cp);
-	if (a) {
-		for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
-		qPainter.drawPolygon(*a);
-		delete a;
-		}
-	if(hgo) hgo->oPolygon(pts, cp);
-	return true;
-}
-
-bool
-PrintQT::oArc(int x1, int y1, int x2, int y2, int quads)
-{
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Find a suitable www browser
-void FindBrowser()
-{
-	//find a suitable browser
-	if(FileExist("/usr/bin/mozilla")) WWWbrowser = strdup("mozilla");
-	else if(FileExist("/usr/bin/netscape")) WWWbrowser = strdup("netscape");
-	else if(FileExist("/usr/bin/konqueror")) WWWbrowser = strdup("konqueror");
-	else if(FileExist("/opt/kde3/bin/konqueror")) WWWbrowser = strdup("konqueror");
-	//use home as startup directory
-	sprintf(TmpTxt, "%s", getenv("HOME"));
-	defs.currPath = strdup(TmpTxt);	strcat(TmpTxt, "/.RLPlot");
-	defs.IniFile = strdup(TmpTxt);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The MAIN antry point
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-int main (int argc, char **argv)
-{
-	QApplication a(argc, argv);
-	DefsRW *drw;
-
-	if(argc > 1 && argv[1]  && argv[1][0] && FileExist(argv[1]))
-		LoadFile = strdup(argv[1]);
-	QAppl = &a;
-	InitTextCursor(true);
-	ShowBanner(true);
-	a.exec();
-	if(defs.IniFile) {
-		if(drw = new DefsRW()){
-			drw->FileIO(FILE_WRITE);		delete drw;
-			}
-		}
-	return 0;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Dialog box support
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-DlgWidget::DlgWidget(QWidget *par, const char *name, tag_DlgObj *d)
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-: QWidget(par, name, Qt::WType_Dialog)
-#else
-: QWidget(par, name, 0x0000002)
-#endif
-{
-	parent = par;
-	dlg = d;
-	setFocusPolicy(StrongFocus);
-}
-
-DlgWidget::~DlgWidget()
-{
-	if(OutputClass){
-		((OutputQT*)OutputClass)->widget=0L;
-		delete ((OutputQT*)OutputClass);
-		}
-}
-
-void
-DlgWidget::paintEvent(QPaintEvent *range)
-{
-	QRect rc;
-
-	rc = range->rect();
-	bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
-		1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
-}
-
-void
-DlgWidget::mouseDoubleClickEvent(QMouseEvent *e)
-{
-	MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
-
-	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-DlgWidget::mousePressEvent(QMouseEvent *e)
-{
-	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
-
-	HideTextCursor();
-	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-DlgWidget::mouseReleaseEvent(QMouseEvent *e)
-{
-	MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP : -1, e->x(), e->y()};
-
-	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-DlgWidget::mouseMoveEvent(QMouseEvent *e)
-{
-	MouseEvent mev = {1, e->state() == Qt::LeftButton ? MOUSE_MOVE : -1, e->x(), e->y()};
-
-	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
-}
-
-void
-DlgWidget::keyPressEvent(QKeyEvent *e)
-{
-	int c;
-
-	if(dlg) switch(c = e->key()) {
-		case Key_Left:
-			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass);
-			else dlg->Command(CMD_CURRLEFT, 0L, OutputClass);
-			break;
-		case Key_Right:
-			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
-			else dlg->Command(CMD_CURRIGHT, 0L, OutputClass);
-			break;
-		case Key_Up:
-			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTUP, 0L, OutputClass);
-			else dlg->Command(CMD_CURRUP, 0L, OutputClass);
-			break;
-		case Key_Down:
-			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTDOWN, 0L, OutputClass);
-			else dlg->Command(CMD_CURRDOWN, 0L, OutputClass);
-			break;
-		case Key_Delete:
-			dlg->Command(CMD_DELETE, 0L, OutputClass);
-			break;
-		case Key_Tab:
-			dlg->Command(CMD_TAB, 0L, OutputClass);
-			break;
-		case Key_Backtab:
-			dlg->Command(CMD_SHTAB, 0L, OutputClass);
-			break;
-		case Key_Home:
-			dlg->Command(CMD_POS_FIRST, 0L, OutputClass);
-			break;
-		case Key_End:
-			dlg->Command(CMD_POS_LAST, 0L, OutputClass);
-			break;
-		default:
-			c = e->ascii();
+
+bool
+PrintQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+	int i;
+
+	QPointArray *a;
+
+	if(!pts || cp <2) return false;
+	a = new QPointArray(cp);
+	if (a) {
+		for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
+		qPainter.drawPolygon(*a);
+		delete a;
+		}
+	if(hgo) hgo->oPolygon(pts, cp);
+	return true;
+}
+
+bool
+PrintQT::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Find a suitable www browser
+void FindBrowser()
+{
+	//find a suitable browser
+	if(FileExist("/usr/bin/mozilla")) WWWbrowser = strdup("mozilla");
+	else if(FileExist("/usr/bin/netscape")) WWWbrowser = strdup("netscape");
+	else if(FileExist("/usr/bin/konqueror")) WWWbrowser = strdup("konqueror");
+	else if(FileExist("/opt/kde3/bin/konqueror")) WWWbrowser = strdup("konqueror");
+	//use home as startup directory
+	sprintf(TmpTxt, "%s", getenv("HOME"));
+	defs.currPath = strdup(TmpTxt);	strcat(TmpTxt, "/.RLPlot");
+	defs.IniFile = strdup(TmpTxt);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The MAIN antry point
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int main (int argc, char **argv)
+{
+	QApplication a(argc, argv);
+	DefsRW *drw;
+
+	if(argc > 1 && argv[1]  && argv[1][0] && FileExist(argv[1]))
+		LoadFile = strdup(argv[1]);
+	QAppl = &a;
+	InitTextCursor(true);
+	ShowBanner(true);
+	a.exec();
+	if(defs.IniFile) {
+		if(drw = new DefsRW()){
+			drw->FileIO(FILE_WRITE);		delete drw;
+			}
+		}
+	return 0;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Dialog box support
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DlgWidget::DlgWidget(QWidget *par, const char *name, tag_DlgObj *d)
+#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
+: QWidget(par, name, Qt::WType_Dialog)
+#else
+: QWidget(par, name, 0x0000002)
+#endif
+{
+	parent = par;
+	dlg = d;
+	setFocusPolicy(StrongFocus);
+}
+
+DlgWidget::~DlgWidget()
+{
+	if(OutputClass){
+		((OutputQT*)OutputClass)->widget=0L;
+		delete ((OutputQT*)OutputClass);
+		}
+}
+
+void
+DlgWidget::paintEvent(QPaintEvent *range)
+{
+	QRect rc;
+
+	rc = range->rect();
+	bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
+		1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
+}
+
+void
+DlgWidget::mouseDoubleClickEvent(QMouseEvent *e)
+{
+	MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
+
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mousePressEvent(QMouseEvent *e)
+{
+	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
+
+	HideTextCursor();
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mouseReleaseEvent(QMouseEvent *e)
+{
+	MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP : -1, e->x(), e->y()};
+
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mouseMoveEvent(QMouseEvent *e)
+{
+	MouseEvent mev = {1, e->state() == Qt::LeftButton ? MOUSE_MOVE : -1, e->x(), e->y()};
+
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::keyPressEvent(QKeyEvent *e)
+{
+	int c;
+
+	if(dlg) switch(c = e->key()) {
+		case Key_Left:
+			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+			else dlg->Command(CMD_CURRLEFT, 0L, OutputClass);
+			break;
+		case Key_Right:
+			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+			else dlg->Command(CMD_CURRIGHT, 0L, OutputClass);
+			break;
+		case Key_Up:
+			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTUP, 0L, OutputClass);
+			else dlg->Command(CMD_CURRUP, 0L, OutputClass);
+			break;
+		case Key_Down:
+			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+			else dlg->Command(CMD_CURRDOWN, 0L, OutputClass);
+			break;
+		case Key_Delete:
+			dlg->Command(CMD_DELETE, 0L, OutputClass);
+			break;
+		case Key_Tab:
+			dlg->Command(CMD_TAB, 0L, OutputClass);
+			break;
+		case Key_Backtab:
+			dlg->Command(CMD_SHTAB, 0L, OutputClass);
+			break;
+		case Key_Home:
+			dlg->Command(CMD_POS_FIRST, 0L, OutputClass);
+			break;
+		case Key_End:
+			dlg->Command(CMD_POS_LAST, 0L, OutputClass);
+			break;
+		default:
+			c = e->ascii();
 			if(c >1 && c < 256)
 				if(c == 26) dlg->Command(CMD_UNDO, 0L, OutputClass);
 				else if(c == 0x03) dlg->Command(CMD_COPY, 0L, OutputClass);
 				else if(c == 0x16) dlg->Command(CMD_PASTE, 0L, OutputClass);
-				else dlg->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
-			break;
-		}
-	e->accept();
-}
-
-void
-DlgWidget::focusInEvent(QFocusEvent *e)
-{
-	CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
-}
-
-void
-DlgWidget::focusOutEvent(QFocusEvent *e)
-{
-	HideTextCursorObj(OutputClass);
-	if(dlg) dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
-}
-
-void
-DlgWidget::closeEvent(QCloseEvent *e)
-{
-	HideTextCursorObj(OutputClass);
-	e->ignore();
-	if(dlg){
-		dlg->Command(CMD_UNLOCK, 0L, OutputClass);
-		dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
-		}
-}
-
-void
-DlgWidget::timerEvent(QTimerEvent *)
-{
-	if(dlg) dlg->Command(CMD_ENDDIALOG, dlg, OutputClass);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags)
-{
-	DlgWidget *w;
-	OutputQT *o;
-	int dw, dh;
-
-	w = new DlgWidget(QAppl->focusWidget(), 0, d);
-	w->setCaption(title);
-	if(flags & 0x2) w->setFixedSize(width, height);
-	else w->setFixedSize(width-6, height-16);
-	if(flags & 0x1) {
-		GetDesktopSize(&dw, &dh);
-		w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1));
-		}
-	else w->move(CurrWidgetPos.x+x, CurrWidgetPos.y+y);
-	o = new OutputQT(w);
-	o->units = defs.cUnits;
-	o->Erase(0x00e0e0e0L);
-	if(flags & 0x04) {
-		w->startTimer(100);
-		}
-	d->DoPlot(o);
-	w->show();
-	return w;
-}
-
-void LoopDlgWnd() 	//keep message processing running
-{
-	QAppl->processOneEvent();
-}
-
-void CloseDlgWnd(void *hDlg)
-{
+				else dlg->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
+			break;
+		}
+	e->accept();
+}
+
+void
+DlgWidget::focusInEvent(QFocusEvent *e)
+{
+	CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
+}
+
+void
+DlgWidget::focusOutEvent(QFocusEvent *e)
+{
+	HideTextCursorObj(OutputClass);
+	if(dlg) dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
+}
+
+void
+DlgWidget::closeEvent(QCloseEvent *e)
+{
+	HideTextCursorObj(OutputClass);
+	e->ignore();
+	if(dlg){
+		dlg->Command(CMD_UNLOCK, 0L, OutputClass);
+		dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
+		}
+}
+
+void
+DlgWidget::timerEvent(QTimerEvent *)
+{
+	if(dlg) dlg->Command(CMD_ENDDIALOG, dlg, OutputClass);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags)
+{
+	DlgWidget *w;
+	QWidget *pw;
+	OutputQT *o;
+	int dw, dh;
+
+	w = new DlgWidget(pw = QAppl->activeWindow(), 0, d);
+	w->setCaption(title);
+	if(flags & 0x2) w->setFixedSize(width, height);
+	else w->setFixedSize(width-6, height-16);
+	if(flags & 0x1) {
+		GetDesktopSize(&dw, &dh);
+		w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1));
+		}
+	else if(pw) {
+		if(pw->x() || pw->y()) {
+			x += pw->x();			y += pw->y();
+			}
+		else {
+			x += CurrWidgetPos.x;	y += CurrWidgetPos.y;
+			}
+		w->move(x, y);
+		}
+	o = new OutputQT(w);	o->units = defs.cUnits;
+	o->Erase(0x00e0e0e0L);	if(flags & 0x04) w->startTimer(100);
+	d->DoPlot(o);			w->show();
+	return w;
+}
+
+void LoopDlgWnd() 	//keep message processing running
+{
+	QAppl->processOneEvent();
+}
+
+void CloseDlgWnd(void *hDlg)
+{
 	HideCopyMark();
-	if(hDlg) {
-		delete((DlgWidget*) hDlg);
-		}
-}
-
-void ShowDlgWnd(void *hDlg)
-{
-	if(hDlg){
-		((DlgWidget*)hDlg)->show();
-		((DlgWidget*)hDlg)->setActiveWindow();
-		((DlgWidget*)hDlg)->raise();
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// OS independent interface to Qt specific classes
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-anyOutput *NewDispClass(GraphObj *g)
-{
-	return new OutputQT(g);
-}
-
-bool DelDispClass(anyOutput *w)
-{
-	if(w) delete (OutputQT*) w;
-	return true;
-}
-
-anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
-{
-	return new BitMapQT(w, h, hr, vr);
-}
-
-bool DelBitmapClass(anyOutput *w)
-{
-	if (w) delete (BitMapQT*) w;
-	return true;
-}
-
+	if(hDlg) {
+		delete((DlgWidget*) hDlg);
+		}
+}
+
+void ShowDlgWnd(void *hDlg)
+{
+	if(hDlg){
+		((DlgWidget*)hDlg)->show();
+		((DlgWidget*)hDlg)->setActiveWindow();
+		((DlgWidget*)hDlg)->raise();
+		}
+}
+
+void ResizeDlgWnd(void *hDlg, int w, int h)
+{
+	((DlgWidget*)hDlg)->setFixedSize(w-6, h-16);
+	((DlgWidget*)hDlg)->show();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// OS independent interface to Qt specific classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *NewDispClass(GraphObj *g)
+{
+	return new OutputQT(g);
+}
+
+bool DelDispClass(anyOutput *w)
+{
+	if(w) delete (OutputQT*) w;
+	return true;
+}
+
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
+{
+	return new BitMapQT(w, h, hr, vr);
+}
+
+bool DelBitmapClass(anyOutput *w)
+{
+	if (w) delete (BitMapQT*) w;
+	return true;
+}
+
diff --git a/QT_Spec.h b/QT_Spec.h
index 43d6c53..ccb1f4c 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -172,8 +172,10 @@ public slots:
 	void cmtEllipse();
 	void cmtArrow();
 	void cmtText();
+	void cmRepCmeans();
 	void cmRepanov();
 	void cmRepregr();
+	void cmReptwoway();
 	void cmFile1() {openHistoryFile(0);};
 	void cmFile2() {openHistoryFile(1);};
 	void cmFile3() {openHistoryFile(2);};
diff --git a/RLPLOT.RC b/RLPLOT.RC
index cdf725d..76f54fd 100755
--- a/RLPLOT.RC
+++ b/RLPLOT.RC
@@ -135,8 +135,10 @@ BEGIN
     END
     POPUP "&Statistics"
     BEGIN
+    	MENUITEM "&Comp. Means"					CM_REPCMEANS
     	MENUITEM "&Anova"						CM_REPANOV
     	MENUITEM "&Regression"					CM_REPREGR
+    	MENUITEM "&2x2 Table"					CM_REPTWOWAY
     END
     POPUP "&Graph"
     BEGIN
diff --git a/TheDialog.cpp b/TheDialog.cpp
index 60dae4e..e3aeeba 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -56,7 +56,7 @@ Dialog *DialogTabStop = 0L;
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Base classes to dialog items
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-DlgRoot::DlgRoot(DlgInfo *tmpl)
+DlgRoot::DlgRoot(DlgInfo *tmpl, DataObj *d)
 {
 	int i;
 	RECT rc;
@@ -68,6 +68,8 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 	bActive = false;	Result = -1;	c_go = CurrGO;
 	CurrDisp = 0L;		oldFocus = DialogFocus;		DialogFocus = 0L;
 	oldDefault = DialogDefault;			oldTabStop = DialogTabStop;
+	data = d;			ParentOut = Undo.cdisp;
+	mrk_item = 0L;		//if an item has a mark its this one
 	if(tmpl) {
 		//count number of items first, then allocate memory
 		for(cDlgs=1;!(tmpl[cDlgs-1].flags & LASTOBJ); cDlgs++);
@@ -96,9 +98,6 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 				case ARROWBUTT:
 					dlg[i]->dialog = new ArrowButton(this, &tmpl[i],rc,(int*)tmpl[i].ptype);
 					break;
-				case COLBUTTON:
-					dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (unsigned long)tmpl[i].ptype);
-					break;
 				case COLBUTT:
 					dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (DWORD *)tmpl[i].ptype);
 					break;
@@ -142,7 +141,7 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 					dlg[i]->dialog = new InputText(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
 					break;
 				case RANGEINPUT:
-					dlg[i]->dialog = new RangeInput(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+					dlg[i]->dialog = new RangeInput(this, &tmpl[i],rc,(char*)tmpl[i].ptype, data);
 					break;
 				case EDVAL1:
 					dlg[i]->dialog = new InputValue(this, &tmpl[i],rc,(double*)tmpl[i].ptype);
@@ -169,7 +168,7 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 					dlg[i]->dialog = new GroupBox(this, &tmpl[i],rc, (char*)tmpl[i].ptype);
 					break;
 				case SHEET:
-					dlg[i]->dialog = new TabSheet(this, &tmpl[i],rc, (TabSHEET *)tmpl[i].ptype);
+					dlg[i]->dialog = new TabSheet(this, &tmpl[i],rc, (TabSHEET *)tmpl[i].ptype, data);
 					break;
 				case ODBUTTON:
 					dlg[i]->dialog = new ODbutton(this, &tmpl[i],rc, tmpl[i].ptype);
@@ -196,6 +195,7 @@ DlgRoot::~DlgRoot()
 {
 	int i;
 
+	if(data) data->Command(CMD_ETRACC, 0L, 0L);
 	if(dlg){
 		for (i = 0; dlg[i] && i < cDlgs; i++) {
 			//we need to delete each object using a cast on its proper type
@@ -205,7 +205,6 @@ DlgRoot::~DlgRoot()
 				case PUSHBUTTON:	delete((PushButton*)dlg[i]->dialog);		break;
 				case TEXTBOX:		delete((TextBox*)dlg[i]->dialog);			break;
 				case ARROWBUTT:		delete((ArrowButton*)dlg[i]->dialog);		break;
-				case COLBUTTON:		delete((ColorButton*)dlg[i]->dialog);		break;
 				case COLBUTT:		delete((ColorButton*)dlg[i]->dialog);		break;
 				case FILLBUTTON:	delete((FillButton*)dlg[i]->dialog);		break;
 				case SHADE3D:		delete((Shade3D*)dlg[i]->dialog);			break;
@@ -246,9 +245,9 @@ DlgRoot::~DlgRoot()
 				}
 			free(dlg[i]);
 			}
-		free(dlg);
+		free(dlg);					dlg=0L;
 		}
-	if(tabstops) free(tabstops);
+	if(tabstops) free(tabstops);	tabstops = 0L;
 	DialogFocus = oldFocus;			DialogDefault = oldDefault;
 	DialogTabStop = oldTabStop;		CurrGO = c_go;
 }
@@ -274,13 +273,14 @@ DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		return true;
 	case CMD_MOUSE_EVENT:
+		if(DialogFocus && DialogFocus->type == TEXTBOX && DialogFocus->Command(cmd, tmpl, o)) return true; 
 		mev = (MouseEvent *) tmpl;
 		switch(mev->Action) {
 		case MOUSE_LBDOWN:
 			bActive = true;
 		case MOUSE_MOVE:
-			if(!(mev->StateFlags & 1))return false;
 			//track mouse and display controls accordingly
+			if(!(mev->StateFlags & 1))return false;
 			if(bActive)ForEach(CMD_MOUSE_EVENT, 0, o);
 			return true;
 		case MOUSE_LBDOUBLECLICK:
@@ -326,13 +326,13 @@ DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
 		HideTextCursor();
 		if(tabstops && DialogTabStop) {
 			for(i = 0; tabstops[i] && tabstops[i] != DialogTabStop && i < cDlgs; i++);
-			if(tabstops[i]) i++;
+			if((tabstops[i]) || (tabstops[i]->flags & HIDDEN)) i++;
 			if(!tabstops[i]) i = 0;
 			switch(tabstops[i]->type) {
 			case PUSHBUTTON:
 				d = DialogDefault;
 				DialogTabStop = DialogDefault = tabstops[i];
-				d->DoPlot(o);
+				if(d) d->DoPlot(o);
 				DialogDefault->DoPlot(o);
 				break;
 			case EDTEXT:			case EDVAL1:	case RANGEINPUT:
@@ -397,6 +397,13 @@ DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
 		for(i = 0; i < cDlgs; i++)
 			if(dlg[i] && dlg[i]->dialog) dlg[i]->dialog->Command(CMD_UNLOCK, 0L, 0L);
 		break;
+	case CMD_MARKOBJ:
+		if(mrk_item && mrk_item != (Dialog*)tmpl){
+			i = 27;
+			mrk_item->Command(CMD_ADDCHAR, &i, o);
+			}
+		mrk_item = (Dialog*)tmpl;
+		break;
 		}
 	return false;
 }
@@ -406,9 +413,9 @@ DlgRoot::DoPlot(anyOutput *o)
 {
 	int i;
 
-	HideCopyMark();
+	HideCopyMark();			mrk_item = 0L;
 	if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
-	if(o)CurrDisp = o;
+	if(o)CurrDisp = o;		DialogDefault = 0L;
 	if(CurrDisp) {
 		CurrDisp->SetTextSpec(&DlgText);
 		ForEach(CMD_DOPLOT, 0, CurrDisp);
@@ -523,12 +530,12 @@ DlgRoot::GetCheck(int Id)
 }
 
 bool
-DlgRoot::GetText(int id, char *txt)
+DlgRoot::GetText(int id, char *txt, int size)
 {
 	int i;
 
 	i = FindIndex(id);
-	if(i && dlg[i]) return dlg[i]->dialog->GetText(id, txt);
+	if(i && dlg[i]) return dlg[i]->dialog->GetText(id, txt, size);
 	return false;
 }
 
@@ -544,6 +551,20 @@ DlgRoot::SetText(int id, char *txt)
 }
 
 bool
+DlgRoot::SetValue(int id, double val)
+{
+	int i;
+	char tmp_txt[80];
+
+	i = FindIndex(id);
+	WriteNatFloatToBuff(tmp_txt, val);
+	if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, tmp_txt+1, CurrDisp)) DoPlot(CurrDisp);
+	else return false;
+	return true;
+}
+
+
+bool
 DlgRoot::TextStyle(int id, int style)
 {
 	int i;
@@ -596,6 +617,7 @@ DlgRoot::GetResult()
 {
 	int ret;
 
+	if(Result >= 0 && ParentOut) Undo.SetDisp(ParentOut);
 	//return each result only once !
 	ret = Result;
 	Result = -1;
@@ -744,8 +766,9 @@ Dialog::MBtrack(MouseEvent *mev, anyOutput *o)
 	case PUSHBUTTON:	case ARROWBUTT:		case CHECKBOX:		case RADIO1:
 	case RADIO2:		case TRASH:			case CONFIG:		case CHECKPIN:
 		if(mev->StateFlags &1) bLBstate = true;
-		if(IsInRect(&hcr, mev->x, mev->y)){
-			if(bLBstate && !bLBdown){
+		if(IsInRect(&hcr, mev->x, mev->y) && bLBstate){
+			if(parent && type != CHECKBOX && type != RADIO1 && type != RADIO2) parent->Command(CMD_MARKOBJ, this, o);
+			if(!bLBdown){
 				bLBdown = bLBstate;			DoPlot(o);
 				return;
 				}
@@ -772,7 +795,7 @@ Dialog::Activate(int id, bool active)
 PushButton::PushButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
-	if(text) Text = strdup(text);
+	if(text && text[0]) Text = (char*)memdup(text, (int)strlen(text)+1, 0);
 	else Text = 0L;
 	TextDef.Align = TXA_HCENTER | TXA_VCENTER;
 }
@@ -800,8 +823,7 @@ PushButton::DoPlot(anyOutput *o)
 {
 	POINT pts[3];
 
-	Line.color = 0x00000000L;
-	Fill.color = DlgBGhigh;
+	Line.color = 0x00000000L;			Fill.color = DlgBGhigh;
 	o->SetLine(&Line);					o->SetFill(&Fill);
 	if(bLBdown) o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
 	else {
@@ -850,14 +872,18 @@ PushButton::Select(int x, int y, anyOutput *o)
 TextBox::TextBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
-	TextDef.Font = FONT_COURIER;
+	lfPOINT lfp1, lfp2;
+
+	TextDef.Font = FONT_COURIER;	TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
 #ifdef _WINDOWS
 //	TextDef.fSize unchanged
 #else
 	TextDef.fSize *= .8;
 #endif
 	Fill.color = 0x00ffffffL;	Line.color = 0x00000000L;	cont = 0L;
-	if(text) cont = new mLabel(0L, 0L, rec.left+3, rec.top+1, &TextDef, text);
+	lfp1.fx = rec.left;				lfp1.fy = rec.top;
+	lfp2.fx = rec.right;			lfp2.fy = rec.bottom;
+	if(cont = new TextFrame(0L, 0L, &lfp1, &lfp2, text)) cont->Command(CMD_SETTEXTDEF, &TextDef, 0L);
 }
 
 TextBox::~TextBox()
@@ -871,23 +897,14 @@ TextBox::Command(int cmd, void *tmpl, anyOutput *o)
 	switch(cmd) {
 	case CMD_CURRLEFT:		case CMD_CURRIGHT:		case CMD_DELETE:
 	case CMD_POS_FIRST:		case CMD_POS_LAST:		case CMD_SHIFTLEFT:
-	case CMD_SHIFTRIGHT:	case CMD_ADDCHAR:
-		if(bChecked && CurrGO && CurrGO->parent == cont){
-			CurrGO->Command(cmd, tmpl, o);
-			DoPlot(o);			o->MrkMode = MRK_NONE;
-			return CurrGO->Command(CMD_REDRAW, 0L, o);	//text cursor !
-			}
-	case CMD_CURRUP:		case CMD_CURRDOWN:
-		if(bChecked && CurrGO && CurrGO->parent == cont){
-			cont->Command(cmd, tmpl, o);
-			DoPlot(o);			o->MrkMode = MRK_NONE;
-			return true;
-			}
+	case CMD_SHIFTRIGHT:	case CMD_ADDCHAR:		case CMD_MOUSE_EVENT:
+	case CMD_COPY:			case CMD_PASTE:			case CMD_CURRUP:
+	case CMD_CURRDOWN:
+		if(bChecked && CurrGO && CurrGO == cont) return CurrGO->Command(cmd, tmpl, o);
 		break;
 	case CMD_SETTEXT:
-		if(cont)DeleteGO(cont);
-		if(tmpl) cont = new mLabel(0L, 0L, cr.left+3, cr.top+1, &TextDef, (char*)tmpl);
-		return true;
+		if(cont)return cont->Command(cmd, tmpl, o);
+		return false;
 		}
 	return false;
 }
@@ -895,10 +912,7 @@ TextBox::Command(int cmd, void *tmpl, anyOutput *o)
 void
 TextBox::DoPlot(anyOutput *o)
 {
-	o->SetLine(&Line);		o->SetFill(&Fill);
-	o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
-	if(cont)cont->DoPlot(o);
-	o->UpdateRect(&cr, false);
+	if(cont && o)cont->DoPlot(o);
 }
 
 bool
@@ -909,15 +923,37 @@ TextBox::Select(int x, int y, anyOutput *o)
 	p1.x = x;			p1.y = y;
 	if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT)) {
 		DialogDefault = DialogFocus = DialogTabStop = this;
-		if(cont) bChecked = cont->Command(CMD_SELECT, &p1, o);
+		if(CurrGO = cont) bChecked = cont->Command(CMD_SELECT, &p1, o);
 		}
 	return false;
 }
 
+void
+TextBox::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+	bool bLBstate;
+	int x, y;
+
+	x = mev->x;						y = mev->y;
+	if(mev->StateFlags &1) bLBstate = true;
+	else bLBstate = false;
+	if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT) && 
+		bLBstate && cont && parent) {
+		DialogFocus = this;			bChecked = true;
+		parent->Command(CMD_FOCTXT, (void*)this, 0L);
+		cont->Command(CMD_MOUSE_EVENT, mev, o);
+		parent->Command(CMD_MARKOBJ, this, o);
+		}
+}
+
 bool
-TextBox::GetText(int id, char *txt)
+TextBox::GetText(int id, char *txt, int size)
 {
-	if(cont) return cont->Command(CMD_ALLTEXT, txt, 0L);
+	if(cont) {
+		if(!(cont->Command(CMD_ALLTEXT, TmpTxt, 0L))) return false;
+		rlp_strcpy(txt, size, TmpTxt);
+		return true;
+		}
 	return false;
 }
 
@@ -1011,16 +1047,11 @@ ArrowButton::Select(int x, int y, anyOutput *o)
 	return false;
 }
 
-ColorButton::ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned long color)
-	:Dialog(par, desc, rec)
-{
-	col = color;
-}
 
 ColorButton::ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, DWORD *color)
 	:Dialog(par, desc, rec)
 {
-	col = *color;
+	col = color ? *color : 0x0L;
 }
 
 void
@@ -1321,7 +1352,7 @@ SymRadioButt::Select(int x, int y, anyOutput *o)
 CheckBox::CheckBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
-	if(text)Text = strdup(text);
+	if(text && text[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
 	else Text = 0L;
 	hcr.left = cr.left+2;		hcr.right = cr.left+14;
 	hcr.top = cr.top+3;			hcr.bottom = cr.top+15;
@@ -1338,7 +1369,7 @@ CheckBox::Command(int cmd, void *tmpl, anyOutput *o)
 	switch(cmd) {
 	case CMD_SETTEXT:
 		if(Text) free(Text);
-		if(tmpl) Text = strdup((char *)tmpl);
+		if(tmpl && *((char*)tmpl)) Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1,0);
 		else Text = 0L;
 		return true;
 		}
@@ -1368,7 +1399,7 @@ CheckBox::DoPlot(anyOutput *o)
 		}
 	if(Text) {
 		o->SetTextSpec(&TextDef);
-		o->oTextOut(cr.left + 20, cr.top + 1, Text, strlen(Text));
+		o->oTextOut(cr.left + 20, cr.top + 1, Text, (int)strlen(Text));
 		}
 	o->UpdateRect(&cr, false);
 }
@@ -1566,7 +1597,7 @@ Config::Select(int x, int y, anyOutput *o)
 RadioButton::RadioButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
-	if(text) Text = strdup(text);
+	if(text && text[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
 	else Text = 0L;
 	switch(type) {
 	case RADIO0:
@@ -1596,7 +1627,7 @@ RadioButton::Command(int cmd, void *tmpl, anyOutput *o)
 	switch(cmd) {
 	case CMD_SETTEXT:
 		if(Text) free(Text);
-		if(tmpl)Text = strdup((char *)tmpl);
+		if(tmpl && *((char*)tmpl))Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 		else Text = 0L;
 		return true;
 		}
@@ -1631,7 +1662,7 @@ RadioButton::DoPlot(anyOutput *o)
 		}
 	if(Text) {
 		o->SetTextSpec(&TextDef);
-		o->oTextOut(cr.left + 20, cr.top + 1, Text, strlen(Text));
+		o->oTextOut(cr.left + 20, cr.top + 1, Text, (int)strlen(Text));
 		}
 	o->UpdateRect(&cr, false);
 }
@@ -1659,7 +1690,7 @@ RadioButton::SetColor(int id, DWORD color)
 Text::Text(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
-	if(text) txt = strdup(text);
+	if(text && text[0])txt = (char*)memdup(text, (int)strlen(text)+1, 0);
 	else txt = 0L;
 	switch (type) {
 	case RTEXT:		TextDef.Align = TXA_HRIGHT | TXA_VTOP;	break;
@@ -1679,7 +1710,7 @@ Text::Command(int cmd, void *tmpl, anyOutput *o)
 	switch(cmd) {
 	case CMD_SETTEXT:
 		if(txt) free(txt);
-		if(tmpl)txt = strdup((char *)tmpl);
+		if(tmpl && *((char*)tmpl))txt = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 		else txt = 0L;
 		return true;
 		}
@@ -1707,9 +1738,13 @@ Text::DoPlot(anyOutput *o)
 bool
 Text::Select(int x, int y, anyOutput *o)
 {
+	int i;
+
 	if(WWWbrowser && WWWbrowser[0] && txt && (flags & HREF) && IsInRect(&cr, x, y)) {
 		o->MouseCursor(MC_WAIT, false);
-		sprintf(TmpTxt, "%s %s", WWWbrowser, txt);
+		i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-50, WWWbrowser);
+		TmpTxt[i++] = ' ';
+		rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, txt);
 		if(parent && (flags & TOUCHEXIT))parent->Command(CMD_ENDDIALOG, 0L, o);
 		else if(parent)parent->Command(CMD_CONTINUE, 0L, o);
 #ifdef _WINDOWS
@@ -1730,6 +1765,12 @@ Text::SetColor(int id, DWORD color)
 	TextDef.ColTxt = color;
 }
 
+void
+Text::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+	if((mev->StateFlags &1) && IsInRect(&hcr, mev->x, mev->y) && parent) parent->Command(CMD_MARKOBJ, this, o);
+}
+
 InputText::InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
 	:Dialog(par, desc, rec)
 {
@@ -1759,6 +1800,7 @@ InputText::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_POS_FIRST:	case CMD_POS_LAST:	case CMD_SHIFTLEFT:
 	case CMD_SHIFTRIGHT:
 		if(Text && bActive && !(flags & NOEDIT)){
+			if(o) Undo.SetDisp(o);
 			o->SetTextSpec(&TextDef);
 			bRet = Text->Command(cmd, o, NULL);
 			if(bRet && (flags & TOUCHEXIT)) parent->Command(CMD_ENDDIALOG, (void *)this, o);
@@ -1776,6 +1818,7 @@ InputText::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_ADDCHAR:
 		if(Text && bActive && !(flags & NOEDIT)){
+			if(o) Undo.SetDisp(o);
 			if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
 			o->SetTextSpec(&TextDef);
 			switch(*((int*)tmpl)) {
@@ -1799,9 +1842,7 @@ InputText::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			WriteNatFloatToBuff(TmpTxt, tmpVal);
 			if(Text) {
-				if(Text->text) free(Text->text);
-				Text->text = strdup(TmpTxt+1);
-				DoPlot(o);
+				Text->SetText(TmpTxt+1);				DoPlot(o);
 				}
 			}
 		break;
@@ -1865,17 +1906,21 @@ InputText::GetInt(int id, int *val)
 		return true;
 		}
 	if(Text && Text->text) {
+#ifdef USE_WIN_SECURE
+		sscanf_s(Text->text, "%d", val);
+#else
 		sscanf(Text->text, "%d", val);
+#endif
 		return true;
 		}
 	return false;
 }
 
 bool
-InputText::GetText(int id, char *txt)
+InputText::GetText(int id, char *txt, int size)
 {
 	if(Text && Text->text && Text->text[0]) {
-		strcpy(txt, Text->text);
+		rlp_strcpy(txt, size, Text->text);
 		return true;
 		}
 	return false;
@@ -1891,11 +1936,12 @@ InputText::MBtrack(MouseEvent *mev, anyOutput *o)
 	if(mev->StateFlags &1) bLBstate = true;
 	else bLBstate = false;
 	if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT) && 
-		bLBstate && Text) {
+		bLBstate && Text && parent) {
 		DialogFocus = this;
-		if(parent) parent->Command(CMD_FOCTXT, (void*)this, 0L);
+		parent->Command(CMD_FOCTXT, (void*)this, 0L);
 		o->SetTextSpec(&TextDef);
 		Text->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+		parent->Command(CMD_MARKOBJ, this, o);
 		}
 }
 
@@ -1914,10 +1960,10 @@ InputText::Activate(int id, bool activate)
 		}
 }
 
-RangeInput::RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+RangeInput::RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d)
 	:InputText(par, desc, rec, text)
 {
-	data = 0L;
+	data = d;
 }
 
 RangeInput::~RangeInput()
@@ -1964,7 +2010,7 @@ InputValue::InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
 	:InputText(par, desc, rec, 0L)
 {
 	WriteNatFloatToBuff(TmpTxt, *value);
-	if(Text) Text->text = strdup(TmpTxt+1);
+	if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
 }
 
 InputValue::~InputValue()
@@ -1984,7 +2030,7 @@ IncDecValue::IncDecValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *valu
 	RECT br;
 
 	WriteNatFloatToBuff(TmpTxt, *value);
-	if(Text) Text->text = strdup(TmpTxt+1);
+	if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
 	br.left = cr.right+1;		br.right = br.left + 7*xbase;
 	br.top = cr.top+1;			br.bottom = br.top + 5*ybase;
 	butts[0] = new ArrowButton(this, &ab[0], br, &ab1);
@@ -2044,24 +2090,30 @@ TxtHSP::TxtHSP(tag_DlgObj *par, DlgInfo *desc, RECT rec, int *align)
 		y2 = ((cr.top>>1) + (cr.bottom>>1))/ybase-4,	y3 = cr.bottom/ybase-8;
 	int i;
 	RECT br;
+	DlgInfo d1[9];
 
-	DlgInfo d1[] = {
-		{1, 2, 0, ISRADIO, RADIO0, 0L, x1, y1, 8, 8},
-		{2, 3, 0, ISRADIO, RADIO0, 0L, x2, y1, 8, 8},
-		{3, 4, 0, ISRADIO, RADIO0, 0L, x3, y1, 8, 8},
-		{4, 5, 0, ISRADIO, RADIO0, 0L, x1, y2, 8, 8},
-		{5, 6, 0, ISRADIO, RADIO0, 0L, x2, y2, 8, 8},
-		{6, 7, 0, ISRADIO, RADIO0, 0L, x3, y2, 8, 8},
-		{7, 8, 0, ISRADIO, RADIO0, 0L, x1, y3, 8, 8},
-		{8, 9, 0, ISRADIO, RADIO0, 0L, x2, y3, 8, 8},
-		{9, 0, 0, ISRADIO | LASTOBJ, RADIO0, 0L, x3, y3, 8, 8}};
-
+	for(i = 0; i < 9; i++) {
+		d1[i].id = i+1;			d1[i].next = i+2;			d1[i].first = 0;
+		d1[i].flags = ISRADIO;	d1[i].type = RADIO0;		d1[i].ptype = 0L;
+		d1[i].w = d1[i].h = 8;
+		switch (i / 3) {
+			case 0:		d1[i].y = y1;	break;
+			case 1:		d1[i].y = y2;	break;
+			case 2:		d1[i].y = y3;	break;
+			}
+		switch (i % 3) {
+			case 0:		d1[i].x = x1;	break;
+			case 1:		d1[i].x = x2;	break;
+			case 2:		d1[i].x = x3;	break;
+			}
+		}
+	d1[8].next = 0;			d1[8].flags |= LASTOBJ;
 	txt.ColTxt = 0x00808080L;	txt.ColBg = 0x00ffffff;
 	txt.fSize = 8.0;		txt.RotBL = txt.RotCHAR = 0.0;
 	txt.iSize = 0;			txt.Align = TXA_HCENTER | TXA_VCENTER;
 	txt.Style = TXS_NORMAL;	txt.Font = FONT_HELVETICA;
 	txt.Mode = TXM_TRANSPARENT;
-	txt.text = strdup("text");
+	if(txt.text = (char*)malloc(20*sizeof(char))) rlp_strcpy(txt.text, 20, "text");
 	if((d2 = (DlgInfo*)malloc(9*sizeof(DlgInfo)))){
 		memcpy(d2, &d1,9*sizeof(DlgInfo));
 		if(align) switch(*align) {
@@ -2526,11 +2578,9 @@ Group::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_FLUSH:
 		if(Children) for(i = 0; i < numChildren; Children[i++] = 0L);
 		break;
-	case CMD_CONTINUE:
-	case CMD_ENDDIALOG:
-	case CMD_TABDLG:
-	case CMD_NOTABDLG:
-		if(parent) return parent->Command(cmd, tmpl, o);
+	case CMD_CONTINUE:		case CMD_ENDDIALOG:		case CMD_TABDLG:
+	case CMD_NOTABDLG:		case CMD_MARKOBJ:
+		if(parent && (flags & HIDDEN) != HIDDEN) return parent->Command(cmd, tmpl, o);
 		else return false;
 	case CMD_ADDCHILD:
 		if(Children && numChildren && (d = (Dialog*)tmpl)) {
@@ -2622,14 +2672,11 @@ Group::MBtrack(MouseEvent *mev, anyOutput *o)
 GroupBox::GroupBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *txt)
 	:Group(par,desc, rec)
 {
-	if(txt)Text = strdup(txt);
+	if(txt && txt[0])Text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
 	else Text = 0L;
-	Line.color = 0x00000000L;
-	Line.width = 0.0;
-	Fill.color = DlgBGhigh;
-	TextDef.ColBg = Fill.color;
-	TextDef.Align = TXA_HLEFT | TXA_VCENTER;
-	TextDef.Mode = TXM_OPAQUE;
+	Line.color = 0x00000000L;					Line.width = 0.0;
+	Fill.color = DlgBGhigh;						TextDef.ColBg = Fill.color;
+	TextDef.Align = TXA_HLEFT | TXA_VCENTER;	TextDef.Mode = TXM_OPAQUE;
 }
 
 GroupBox::~GroupBox()
@@ -2652,17 +2699,15 @@ GroupBox::DoPlot(anyOutput *o)
 	o->UpdateRect(&hcr, false);
 }
 
-TabSheet::TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET * sh)
+TabSheet::TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET * sh, DataObj *d)
 	:Group(par, desc, rec)
 {
-	if(sh->text)Text = strdup(sh->text);
+	if(sh->text && sh->text[0])Text = (char*)memdup(sh->text, (int)strlen(sh->text)+1, 0);
 	else Text = 0L;
-	rctab.left = cr.left + sh->x1 * xbase;
-	rctab.right = cr.left + sh->x2 * xbase;
-	rctab.top = cr.top;
-	rctab.bottom = cr.top + sh->height * ybase;
-	TextDef.Align = TXA_HRIGHT | TXA_VTOP;
-	flags |= ISRADIO;
+	rctab.left = cr.left + sh->x1 * xbase;			rctab.right = cr.left + sh->x2 * xbase;
+	rctab.top = cr.top;								rctab.bottom = cr.top + sh->height * ybase;
+	TextDef.Align = TXA_HRIGHT | TXA_VTOP;			flags |= ISRADIO;
+	data = d;
 }
 
 TabSheet::~TabSheet()
@@ -2709,9 +2754,12 @@ bool
 TabSheet::Select(int x, int y, anyOutput *o)
 {
 	if(IsInRect(&rctab, x, y)) {
-		if(parent) parent->Command(CMD_RADIOBUTT, (void *)this, o);
-		bChecked = true;
-		DoPlot(o);
+		if(data)data->Command(CMD_ETRACC, 0L, 0L);
+		if(parent) {
+			parent->Command(CMD_RADIOBUTT, (void *)this, o);
+			parent->Command(CMD_MARKOBJ, this, o);
+			}
+		bChecked = true;		DoPlot(o);
 		if((flags & TOUCHEXIT) && parent) 
 			parent->Command(CMD_ENDDIALOG, (void *)this, o);
 		return true;
@@ -2791,7 +2839,9 @@ Listbox::Listbox(tag_DlgObj *par, DlgInfo *des, RECT rec, char **list)
 	Fill.color = 0x00ffffffL;			Line.color = 0x00000000L;
 	for(i = ns = 0; list && list[i]; i++);	//count lines
 	if(strings = (char **)calloc(i+1, sizeof(char*))){
-		for(ns = i, i = 0; i < ns; strings[i] = strdup(list[i]), i++);
+		for(ns = i, i = 0; i < ns; i++){
+			strings[i] = (char*)memdup(list[i], (int)strlen(list[i])+1, 0);
+			}
 		}
 }
 
@@ -2908,10 +2958,10 @@ Listbox::GetInt(int id, int *val)
 }
 
 bool
-Listbox::GetText(int id, char *txt)
+Listbox::GetText(int id, char *txt, int size)
 {
 	if(strings && ns && cl >= 0 && cl < ns){
-		strcpy(txt, strings[cl]);
+		rlp_strcpy(txt, size, strings[cl]);
 		return true;
 		}
 	return false;
@@ -3145,7 +3195,7 @@ static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<
 
 DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 {
-	char **lines, **fields, **flags;
+	char **lines, **fields, **flags, error[80];
 	int i, j, nlines, nfields, nflags;
 	unsigned int hv;
 	DlgInfo *Dlg;
@@ -3157,8 +3207,14 @@ DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 		if(fields = split(lines[i], ',', &nfields)) {
 			if(nfields == 10) {
 				Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+#ifdef USE_WIN_SECURE
+				sscanf_s(fields[0], "%d", &Dlg[i].id);		sscanf_s(fields[1], "%d", &Dlg[i].next);
+				sscanf_s(fields[2], "%d", &Dlg[i].first);
+#else
 				sscanf(fields[0], "%d", &Dlg[i].id);		sscanf(fields[1], "%d", &Dlg[i].next);
-				sscanf(fields[2], "%d", &Dlg[i].first);		Dlg[i].flags = 0L;
+				sscanf(fields[2], "%d", &Dlg[i].first);
+#endif
+				Dlg[i].flags = 0L;
 				if(flags = split(fields[3], '|', &nflags)) {
 					for(j = 0; j < nflags; j++){
 						hv = HashValue((unsigned char *)str_trim(flags[j]));
@@ -3186,7 +3242,6 @@ DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 				switch(hv) {
 				case 17108522:		Dlg[i].type = PUSHBUTTON;	break;
 				case 3252180:		Dlg[i].type = ARROWBUTT;	break;
-				case 3296810:		Dlg[i].type = COLBUTTON;	break;
 				case 206036:		Dlg[i].type = COLBUTT;		break;
 				case 13602346:		Dlg[i].type = FILLBUTTON;	break;
 				case 261312:		Dlg[i].type = SHADE3D;		break;
@@ -3222,12 +3277,32 @@ DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 				case 51627:			Dlg[i].type = CONFIG;		break;
 				default:			Dlg[i].type = NONE;			break;
 					}
+#ifdef USE_WIN_SECURE
+				sscanf_s(fields[5], "%d", &j);
+#else
 				sscanf(fields[5], "%d", &j);
+#endif
 				if(j < 0) Dlg[i].ptype = (void*)std_text[(-j)-1];
 				else if(j > 0) Dlg[i].ptype = ptypes[j-1];
 				else Dlg[i].ptype = (void*)0L;
+#ifdef USE_WIN_SECURE
+				sscanf_s(fields[6], "%d", &Dlg[i].x);	sscanf_s(fields[7], "%d", &Dlg[i].y);
+				sscanf_s(fields[8], "%d", &Dlg[i].w);	sscanf_s(fields[9], "%d", &Dlg[i].h);
+#else
 				sscanf(fields[6], "%d", &Dlg[i].x);		sscanf(fields[7], "%d", &Dlg[i].y);
 				sscanf(fields[8], "%d", &Dlg[i].w);		sscanf(fields[9], "%d", &Dlg[i].h);
+#endif
+				}
+			else {
+#ifdef USE_WIN_SECURE
+				sprintf_s(error, 80, "Wrong number of arguments in template line %d", i);
+#else
+				sprintf(error,"Wrong number of arguments in template line %d", i);
+#endif
+				InfoBox(error);
+				Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+				Dlg[i].flags = 0L;		Dlg[i].type = NONE;
+				Dlg[i].ptype = 0L;		Dlg[i].x = Dlg[i].y = Dlg[i].w = Dlg[i].h = 0;
 				}
 			for(j = 0; j < nfields; j++)free(fields[j]);
 			free(fields);
@@ -3246,12 +3321,13 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 {
 	char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
 	char *mrk, **ra =0L;;
-	int i, j, ranges=0;
+	int i, j, k, ranges=0;
 	bool success = false;
 	RECT vrc;
 	AccRange *ar;
 	bool bRet = true;
 
+	for(i = 0; i < 11; i++) if(dst[i]) *dst[i] = 0;
 	if(d && type) {
 		d->ValueRec(&vrc);
 		if(d->Command(CMD_GETMARK, &mrk, 0L)) {
@@ -3262,8 +3338,47 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 		case 1:
 			if(ranges > 1) {
 				for(i = 0; i < 11; i++) if(dst[i]) {
+#ifdef USE_WIN_SECURE
+					if(i < ranges) sprintf_s(dst[i], 100, "%s", ra[i]);
+					else {
+						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1);
+						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left, false), vrc.bottom+1);
+						}
+#else
 					if(i < ranges) sprintf(dst[i], "%s", ra[i]);
-					else sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+					else {
+						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1);
+						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left, false), vrc.bottom+1);
+						}
+#endif
+					}
+				success = true;
+				}
+			else if(vrc.top == vrc.bottom && (vrc.right - vrc.left) >2) {
+				for(i = 0; i < 11; i++) {
+					if(dst[i]){
+#ifdef USE_WIN_SECURE
+						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1+i);
+						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.right, false), vrc.top+1+i);
+#else
+						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1+i);
+						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.right, false), vrc.top+1+i);
+#endif
+						}
+					}
+				success = true;
+				}
+			else if(vrc.right == vrc.left && (vrc.bottom - vrc.top) >2) {
+				for(i = 0; i < 11; i++) {
+					if(dst[i]){
+#ifdef USE_WIN_SECURE
+						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#else
+						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#endif
+						}
 					}
 				success = true;
 				}
@@ -3271,8 +3386,14 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 		case 2:
 			for(i = 0; i < 11; i++) if(dst[i]) *(dst[i]) = 0;
 			if(ranges == 1) {
-				for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) {
-					if(dst[i])sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+				for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) if(dst[i]){
+#ifdef USE_WIN_SECURE
+					k = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+					sprintf_s(dst[i]+k, 100-k, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#else
+					k = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+					sprintf(dst[i]+k, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#endif
 					}
 				}
 			else if(ranges > 1) {
@@ -3287,7 +3408,7 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 					delete ar;
 					}
 				if(i < 12) for(i = 0; i < 11 && i < ranges; i++){
-					if(dst[i]) strcpy(dst[i], ra[i]);
+					if(dst[i]) rlp_strcpy(dst[i], 100, ra[i]);
 					}
 				}
 			success = true;
@@ -3297,7 +3418,15 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 		vrc.left = vrc.top = 0;		vrc.right = vrc.bottom = 9;
 		}
 	if(!success) for(i = 0; i < 11; i++) {
-		if(dst[i])sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+ 		if(dst[i]){
+#ifdef USE_WIN_SECURE
+			j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+			sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#else
+			j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
+			sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
+#endif
+			}
 		}
 	if(ra) {
 		for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
@@ -3322,38 +3451,42 @@ DWORD GetNewColor(DWORD oldColor)
 		"7, 0, 8, CHECKED | ISPARENT, GROUP, 0, 0, 0, 0, 0";
 	void *ptypes[] = {(void*)" RGB "};
 	DlgInfo *ColDlg = CompileDialog(NewColorTmpl, ptypes);
-	DWORD currcol, newcol;
+	DWORD currcol, newcol, palette[230];
 	int ilevels[] = {0x0, 0x40, 0x80, 0xc0, 0xe0, 0xff};
-	int i, ir, ig, ib, col, row, res;
+	int i, j, ir, ig, ib, col, row, res;
 	DlgRoot *Dlg;
 	void *hDlg;
 
 	if(!(ColDlg = (DlgInfo *)realloc(ColDlg, 230 * sizeof(DlgInfo))))return oldColor;
-	for(ir=row=col=0, i= 7; ir<6; ir++) for(ig=0; ig<6; ig++) for(ib=0; ib<6; ib++) {
+	for(ir=row=col=0, i=7, j=0; ir<6; ir++) for(ig=0; ig<6; ig++) for(ib=0; ib<6; ib++) {
 		ColDlg[i].id = i+1;					ColDlg[i].next = i+2;
-		ColDlg[i].type = COLBUTTON;			ColDlg[i].first = 0;
-		currcol = (ilevels[ib]<<16)|(ilevels[ig]<<8)|(ilevels[ir]);
+		ColDlg[i].type = COLBUTT;			ColDlg[i].first = 0;
+		palette[j] = currcol = (ilevels[ib]<<16)|(ilevels[ig]<<8)|(ilevels[ir]);
 		ColDlg[i].flags = TOUCHEXIT | ISRADIO;
 		if(currcol == oldColor) ColDlg[i].flags |= CHECKED;
-		ColDlg[i].ptype = (void *)currcol;
+		ColDlg[i].ptype = (void *)&palette[j];
 		ColDlg[i].x = 5 + col*10;			ColDlg[i].y = 5 + row*10;
 		ColDlg[i].w = ColDlg[i].h = 10;
 		col++;
 		if(col >= 18) {
 			col = 0;			row++;
 			}
-		i++;
+		i++, j++;
 		}
+	j=j;
 	ColDlg[i-1].next = 0;
 	ColDlg[i-1].flags |= LASTOBJ;
 	newcol = currcol = oldColor;
-	Dlg = new DlgRoot(ColDlg);
-	sprintf(TmpTxt, "R: 0x%02x", currcol & 0xff);
-	Dlg->SetText(4, TmpTxt);
-	sprintf(TmpTxt, "G: 0x%02x", (currcol>>8) & 0xff);
-	Dlg->SetText(5, TmpTxt);
-	sprintf(TmpTxt, "B: 0x%02x", (currcol>>16) & 0xff);
-	Dlg->SetText(6, TmpTxt);
+	Dlg = new DlgRoot(ColDlg, 0L);
+#ifdef USE_WIN_SECURE
+	sprintf_s(TmpTxt, 10, "R: 0x%02x", currcol & 0xff);				Dlg->SetText(4, TmpTxt);
+	sprintf_s(TmpTxt, 10, "G: 0x%02x", (currcol>>8) & 0xff);		Dlg->SetText(5, TmpTxt);
+	sprintf_s(TmpTxt, 10, "B: 0x%02x", (currcol>>16) & 0xff);		Dlg->SetText(6, TmpTxt);
+#else
+	sprintf(TmpTxt, "R: 0x%02x", currcol & 0xff);			Dlg->SetText(4, TmpTxt);
+	sprintf(TmpTxt, "G: 0x%02x", (currcol>>8) & 0xff);		Dlg->SetText(5, TmpTxt);
+	sprintf(TmpTxt, "B: 0x%02x", (currcol>>16) & 0xff);		Dlg->SetText(6, TmpTxt);
+#endif
 	hDlg = CreateDlgWnd("Select color", 50, 50, 510, 310, Dlg,0x0L);
 	do {
 		LoopDlgWnd();
@@ -3371,12 +3504,15 @@ DWORD GetNewColor(DWORD oldColor)
 				currcol = newcol;
 				if(Dlg->GetColor(res, &newcol) && currcol != newcol) {
 					res = -1;
-					sprintf(TmpTxt, "R: 0x%02x", newcol & 0xff);
-					Dlg->SetText(4, TmpTxt);
-					sprintf(TmpTxt, "G: 0x%02x", (newcol>>8) & 0xff);
-					Dlg->SetText(5, TmpTxt);
-					sprintf(TmpTxt, "B: 0x%02x", (newcol>>16) & 0xff);
-					Dlg->SetText(6, TmpTxt);
+#ifdef USE_WIN_SECURE
+					sprintf_s(TmpTxt, 10, "R: 0x%02x", newcol & 0xff);				Dlg->SetText(4, TmpTxt);
+					sprintf_s(TmpTxt, 10, "G: 0x%02x", (newcol>>8) & 0xff);			Dlg->SetText(5, TmpTxt);
+					sprintf_s(TmpTxt, 10, "B: 0x%02x", (newcol>>16) & 0xff);		Dlg->SetText(6, TmpTxt);
+#else
+					sprintf(TmpTxt, "R: 0x%02x", newcol & 0xff);					Dlg->SetText(4, TmpTxt);
+					sprintf(TmpTxt, "G: 0x%02x", (newcol>>8) & 0xff);				Dlg->SetText(5, TmpTxt);
+					sprintf(TmpTxt, "B: 0x%02x", (newcol>>16) & 0xff);				Dlg->SetText(6, TmpTxt);
+#endif
 					}
 				}
 			break;
@@ -3395,9 +3531,9 @@ static char *ConfShade_DlgTmpl =
 	"1,2,,DEFAULT,PUSHBUTTON,-1,95,10,45,12\n"
 	"2,3,,,PUSHBUTTON,-2,95,25,45,12\n"
 	"3,4,100,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
-	"4,5,,OWNDIALOG | TOUCHEXIT,COLBUTT,1,60,10,15,10\n"
-	"5,6,,OWNDIALOG | TOUCHEXIT,COLBUTT,2,60,37,15,10\n"
-	"6,7,,OWNDIALOG | TOUCHEXIT,COLBUTT,1,60,49,15,10\n"
+	"4,5,,ODEXIT,COLBUTT,1,60,10,15,10\n"
+	"5,6,,ODEXIT,COLBUTT,2,60,37,15,10\n"
+	"6,7,,ODEXIT,COLBUTT,1,60,49,15,10\n"
 	"7,8,,,RTEXT,3,25,37,30,9\n"
 	"8,9,,,RTEXT,4,25,49,30,9\n"
 	"9,,,,SHADE3D,5,95,50,22,20\n"
@@ -3420,7 +3556,7 @@ void ConfShade(FillDEF *oldfill)
 	if(!oldfill) return;
 	memcpy(&newFill, oldfill, sizeof(FillDEF));
 	newFill.type = FILL_LIGHT3D;
-	if(!(Dlg = new DlgRoot(ShadeDlg))) return;
+	if(!(Dlg = new DlgRoot(ShadeDlg, 0L))) return;
 	if(oldfill->type & FILL_LIGHT3D) Dlg->SetCheck(101, 0L, true);
 	else {
 		Dlg->SetCheck(100, 0L, true);
@@ -3488,12 +3624,12 @@ void GetNewFill(FillDEF *oldfill)
 		{102, 103, 0, TOUCHEXIT, INCDECVAL1, &PrevLine.width, 119, 95, 32, 10},
 		{103, 104, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 152, 95, 15, 8},
 		{104, 105, 0, 0x0L, RTEXT, (void*)"line color", 5, 95, 30, 8},
-		{105, 106, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, 0x0L, 36, 95, 25, 10},
+		{105, 106, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, 0x0L, 36, 95, 25, 10},
 		{106, 107, 0, 0x0L, RTEXT, (void*)"pattern size", 78, 110, 40, 8},
 		{107, 108, 0, TOUCHEXIT, INCDECVAL1, (void*)&fscale, 119, 110, 32, 10},
 		{108, 109, 0, 0x0L, LTEXT, (void*)"%", 152, 110, 8, 8},
 		{109, 110, 0, 0x0L, RTEXT, (void*)"BG color", 5, 110, 30, 8},
-		{110, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, 0x0L, 36, 110, 25, 10}};
+		{110, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, 0x0L, 36, 110, 25, 10}};
 	DlgInfo *FillDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
@@ -3526,7 +3662,7 @@ void GetNewFill(FillDEF *oldfill)
 		FillDlg[i-1].flags |= LASTOBJ;
 		}
 	else return;
-	Dlg = new DlgRoot(FillDlg);
+	Dlg = new DlgRoot(FillDlg, 0L);
 	for(i = Dlg->FindIndex(500), j = 0; FillDlg[i].type == FILLRADIO; i++, j++)
 		if(*((int*)FillDlg[i].ptype) == PrevFill.type)Dlg->SetCheck(500+j, 0L, true);
 	Dlg->SetColor(105, PrevLine.color);
@@ -3621,8 +3757,8 @@ bool ShowLayers(GraphObj *root)
 	GraphObj *cgo = 0L;
 
 	if(!root) return false;
-	sprintf(curr_name, "(root)");
-	if(!(Dlg = new DlgRoot(PageDlg)))return false;
+	rlp_strcpy(curr_name, 50, "(root)");
+	if(!(Dlg = new DlgRoot(PageDlg, 0L)))return false;
 	Dlg->ItemCmd(100, CMD_OBJTREE, &ot);
 	if(!ot) {
 		delete Dlg;			return false;
@@ -3721,7 +3857,7 @@ void ShowBanner(bool show)
 	int res, cnt = 5;
 
 	if(!show) return;
-	if(!(Dlg = new DlgRoot(BannerDlg)))return;
+	if(!(Dlg = new DlgRoot(BannerDlg, 0L)))return;
 #ifdef _WINDOWS
 	Dlg->TextSize(3, 36);
 #else
@@ -3795,7 +3931,7 @@ void RLPlotInfo()
 	void *hDlg;
 	int res;
 
-	if((Dlg = new DlgRoot(AboutDlg))) {
+	if((Dlg = new DlgRoot(AboutDlg, 0L))) {
 		Dlg->TextStyle(3, TXS_ITALIC | TXS_BOLD);
 		Dlg->TextFont(3, FONT_TIMES);
 #ifdef _WINDOWS
@@ -3868,8 +4004,12 @@ DoSpShSize(DataObj *dt)
 	default:	ch = NiceValue(((double)(celldim[2]-2))*0.259183673);	break;
 		}
 	ch1 = ch;						th = th1 = defs.ss_txt*100.0;
-	sprintf(txt1, "%d", w1);		sprintf(txt2, "%d", h1);
-	Dlg = new DlgRoot(SSDlg);
+#ifdef USE_WIN_SECURE
+	sprintf_s(txt1, 40, "%d", w1);		sprintf_s(txt2, 40, "%d", h1);
+#else
+	sprintf(txt1, "%d", w1);			sprintf(txt2, "%d", h1);
+#endif
+	Dlg = new DlgRoot(SSDlg, dt);
 	hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 320, 220, Dlg, 0x0L);
 	Dlg->GetValue(201, &fw1);	Dlg->GetValue(204, &cw1);	Dlg->GetValue(207, &ch1);
 	do{
@@ -3877,7 +4017,7 @@ DoSpShSize(DataObj *dt)
 		res = Dlg->GetResult();
 		switch(res) {
 		case 1:					//OK pressed
-			if(Dlg->GetText(101, txt1) && Dlg->GetText(103, txt2)) {
+			if(Dlg->GetText(101, txt1, 40) && Dlg->GetText(103, txt2, 40)) {
 				w2 = atol(txt1);		h2 = atol(txt2);
 				w2 = w2 > 0 ? w2: w1;	h2 = h2 > 0 ? h2: h1;
 				}
@@ -3923,11 +4063,11 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 	TabSHEET tab1 = {0, 37, 10, "fill range "};
 	char *ra = range ? *range:0L;
 	double startval = 1.0, stepval = 1.0;
-	static char *formula = 0L;
-	if(!formula && CurrText && CurrText->isFormula()) {
-		if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE, false)) formula = strdup(TmpTxt);
+	static char *formula = (char*)malloc(500 * sizeof(char));
+	if(formula && CurrText && CurrText->isFormula()) {
+		if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE, false)) rlp_strcpy(formula, 500, TmpTxt);
 		}
-	if(!formula) formula = strdup("=a1");
+	if(formula) rlp_strcpy(formula, 500, "=a1");
 	DlgInfo RangeDlg[] = {
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 162, 5, 38, 12},
 		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 162, 20, 38, 12},
@@ -3956,8 +4096,7 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 	anyOutput *cdisp = 	Undo.cdisp;
 
 	if(!d || !range) return false;
-	if(!(Dlg = new DlgRoot(RangeDlg))) return false;
-	Dlg->ItemCmd(6, CMD_SET_DATAOBJ, d);
+	if(!(Dlg = new DlgRoot(RangeDlg, d))) return false;
 #ifdef _WINDOWS
 	for(i = 23; i <= 24; i++) Dlg->TextSize(i, 12);
 #else
@@ -3976,11 +4115,11 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 			break;
 		case 1:
 			ra = 0L;
-			if(!Dlg->GetText(6, TmpTxt)) {
+			if(!Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE)) {
 				InfoBox("Range not specified\nor not valid.");
 				bContinue = true;				res = -1;
 				}
-			else ra = strdup(TmpTxt);
+			else ra = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 			rc_dest.left = rc_dest.right = rc_dest.top = rc_dest.bottom = 0;
 			break;
 		case 7:
@@ -4011,9 +4150,9 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 				}
 			}
 		else if(Dlg->GetCheck(8)) {
-			if(formula) free(formula);	formula = 0L;
 			if((rF = new AccRange(ra)) && rF->GetFirst(&col, &row) && 
-				Dlg->GetText(22, TmpTxt) && (formula = strdup(TmpTxt))){
+				Dlg->GetText(22, TmpTxt, TMP_TXT_SIZE) && formula){
+				rlp_strcpy(formula, 500, TmpTxt);
 				r1 = row;		c1 = col;
 				for( ; rF->GetNext(&col, &row); startval += stepval) {
 					if(formula[0] == '=') {
@@ -4054,7 +4193,7 @@ bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
 	bool bRet = false;
 	int res;
 	
-	if(!(Dlg = new DlgRoot(ResDlg))) return false;
+	if(!(Dlg = new DlgRoot(ResDlg, 0L))) return false;
 	if(!(hDlg = CreateDlgWnd(header, 50, 50, 300, 160, Dlg, 0x0L)))return false;
 	do {
 		LoopDlgWnd();
@@ -4121,11 +4260,11 @@ void OD_scheme(int cmd, void *par, RECT *rec, anyOutput *o,
 			for (k = 20, j = 6; k < 50; k += 10) {
 				for(i = 0; i < 8; i++) {
 					ComSchDlg[j].id = i+k;				ComSchDlg[j].next = i+k+1;
-					ComSchDlg[j].type = k < 40 ? COLBUTTON : FILLBUTTON;		
+					ComSchDlg[j].type = k < 40 ? COLBUTT : FILLBUTTON;		
 					ComSchDlg[j].flags = OWNDIALOG | TOUCHEXIT;
 					switch(k) {
-					case 20:	ComSchDlg[j].ptype = (void *)Scheme1[i];	break;
-					case 30:	ComSchDlg[j].ptype = (void *)Scheme2[i];	break;
+					case 20:	ComSchDlg[j].ptype = (void *)&Scheme1[i];	break;
+					case 30:	ComSchDlg[j].ptype = (void *)&Scheme2[i];	break;
 					case 40:	ComSchDlg[j].ptype = (void *)&Scheme3[i];	break;
 						}
 					ComSchDlg[j].x = 5 + i*9 + x;		ComSchDlg[j].y = 18*(k-10)/10 + y;
@@ -4135,7 +4274,7 @@ void OD_scheme(int cmd, void *par, RECT *rec, anyOutput *o,
 				ComSchDlg[j-1].next = k+10;
 				}
 			ComSchDlg[j-1].next = 0;	ComSchDlg[j-1].flags |= LASTOBJ;
-			Dlg = new DlgRoot(ComSchDlg);
+			Dlg = new DlgRoot(ComSchDlg, 0L);
 			}
 		if(Dlg){
 			if(CurrScheme < 4) Dlg->SetCheck(5+CurrScheme, 0L, true);
@@ -4216,7 +4355,7 @@ static DlgInfo LinePropBase[] = {
 	{101, 102, 0, TOUCHEXIT, INCDECVAL1, &EditLine.width, 50, 0, 32, 10},
 	{102, 103, 0, 0x0L, LTEXT, 0L, 84, 0, 20, 8},
 	{103, 104, 0, 0x0L, RTEXT, (void*)"line color", 0, 12, 45, 8},
-	{104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)EditLine.color, 50, 12, 25, 10},
+	{104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&EditLine.color, 50, 12, 25, 10},
 	{105, 106, 0, 0x0L, LTEXT, (void*)"pattern:", 0, 24, 25, 8},
 	{106, 107, 0, TOUCHEXIT, LINEPAT, (void *)&EditLine, 0, 34, 128, 4},
 	{107, 108, 0, 0x0L, RTEXT, (void*)"pattern length", 0, 47, 45, 8},
@@ -4245,7 +4384,7 @@ void OD_linedef(int cmd, void *par, RECT *rec, anyOutput *o,
 			for (i = 0; i < 11; i++) {
 				LinePropDlg[i].x += x;	LinePropDlg[i].y += y;
 				}
-			Dlg = new DlgRoot(LinePropDlg);
+			Dlg = new DlgRoot(LinePropDlg, 0L);
 			}
 		if(Dlg){
 			Dlg->SetColor(104, EditLine.color);
@@ -4318,9 +4457,9 @@ static DlgInfo FillPropBase[] = {
 	{101, 102, 0, 0x0L, EDVAL1, &ODLine.width, 42, 0, 25, 10},
 	{102, 103, 0, 0x0L, LTEXT, 0L, 69, 0, 20, 8},
 	{103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 0, 12, 40, 8},
-	{104, 105, 0, OWNDIALOG, COLBUTTON, (void *)ODLine.color, 42, 12, 25, 10},
+	{104, 105, 0, OWNDIALOG, COLBUTT, (void *)&ODLine.color, 42, 12, 25, 10},
 	{105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 0, 24, 40, 8},
-	{106, 107, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ODFill.color, 42, 24, 25, 10},
+	{106, 107, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ODFill.color, 42, 24, 25, 10},
 	{107, 108, 0, 0x0L, RTEXT, (void*)"pattern", 0, 36, 40, 8},
 	{108, 0, 0, LASTOBJ | TOUCHEXIT | OWNDIALOG, FILLBUTTON, (void*)&ODFill, 42, 36, 25, 10}};
 
@@ -4344,7 +4483,7 @@ void OD_filldef(int cmd, void *par, RECT *rec, anyOutput *o,
 			for (i = 0; i < 9; i++) {
 				FillPropDlg[i].x += x;	FillPropDlg[i].y += y;
 				}
-			Dlg = new DlgRoot(FillPropDlg);
+			Dlg = new DlgRoot(FillPropDlg, 0L);
 			}
 		if(Dlg){
 			Dlg->SetColor(104, ODLine.color);
@@ -4475,21 +4614,37 @@ void OD_paperdef(int cmd, void *par, RECT *rec, anyOutput *o,
 				if(i < cpformats -1) {
 					switch(defs.cUnits) {
 					case 1:
+#ifdef USE_WIN_SECURE
+						sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s  (%.1lf x %.1lf cm)", p_formats[i].name, 
+							p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
+#else
 						sprintf(TmpTxt, " %s  (%.1lf x %.1lf cm)", p_formats[i].name, 
 							p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
+#endif
 						break;
 					case 2:
+#ifdef USE_WIN_SECURE
+						sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s  (%.2lf x %.2lf inch)", p_formats[i].name, 
+							p_formats[i].iwidth, p_formats[i].iheight);
+#else
 						sprintf(TmpTxt, " %s  (%.2lf x %.2lf inch)", p_formats[i].name, 
 							p_formats[i].iwidth, p_formats[i].iheight);
+#endif
 						break;
 					default:
+#ifdef USE_WIN_SECURE
+						sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s  (%.0lf x %.0lf mm)", p_formats[i].name, 
+							p_formats[i].mwidth, p_formats[i].mheight);
+#else
 						sprintf(TmpTxt, " %s  (%.0lf x %.0lf mm)", p_formats[i].name, 
 							p_formats[i].mwidth, p_formats[i].mheight);
+#endif
 						break;
 						}
-					dispsize[i] = strdup(TmpTxt);
+					dispsize[i] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
 					}
-				else dispsize[i] = strdup(" Custom");
+				else if(dispsize[i] = (char*)malloc(15*sizeof(char)))
+					rlp_strcpy(dispsize[i], 15, " Custom");
 				}
 			PaperPropDlg[1].ptype = (void*)dispsize;
 			PaperPropDlg[7].ptype = (void*)Units[defs.cUnits].display;
@@ -4497,7 +4652,7 @@ void OD_paperdef(int cmd, void *par, RECT *rec, anyOutput *o,
 			for (i = 0; i < 8; i++) {
 				PaperPropDlg[i].x += x;	PaperPropDlg[i].y += y;
 				}
-			if(Dlg = new DlgRoot(PaperPropDlg)){
+			if(Dlg = new DlgRoot(PaperPropDlg, 0L)){
 				Dlg->Activate(120, false);
 				if(Dlg->ItemCmd(110, CMD_FINDTEXT, (void*)dispsize[pg_sel])){
 					if(pg_sel < (cpformats-1)) Dlg->SetText(120, dispsize[pg_sel]);
@@ -4532,7 +4687,7 @@ void OD_paperdef(int cmd, void *par, RECT *rec, anyOutput *o,
 			((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
 			Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
 			res = Dlg->GetResult();
-			if(res == 110 && Dlg->GetText(110, TmpTxt)){
+			if(res == 110 && Dlg->GetText(110, TmpTxt, TMP_TXT_SIZE)){
 				if(Dlg->GetInt(110, &i)) {
 					if(i == cpformats-1){
 						Dlg->ShowItem(130, true);
@@ -4677,7 +4832,7 @@ void OD_axisplot(int cmd, void *par, RECT *rec, anyOutput *o,
 		if(PlotsPropDlg = (DlgInfo*)calloc(3, sizeof(DlgInfo))){
 			memcpy(PlotsPropDlg, PlotsDlg, 3 * sizeof(DlgInfo));
 			PlotsPropDlg[1].ptype = (void*)names;
-			Dlg = new DlgRoot(PlotsPropDlg);
+			Dlg = new DlgRoot(PlotsPropDlg, 0L);
 			}
 		axisplot_sel = 0;
 		break;
@@ -4700,7 +4855,7 @@ void OD_axisplot(int cmd, void *par, RECT *rec, anyOutput *o,
 			((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
 			Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
 			res = Dlg->GetResult();
-			if(res == 110 && Dlg->GetText(110, TmpTxt)){
+			if(res == 110 && Dlg->GetText(110, TmpTxt, TMP_TXT_SIZE)){
 				if(Dlg->GetInt(110, &i)) {
 					//get selection
 					}
diff --git a/TheDialog.h b/TheDialog.h
index c21e44c..ad8ac0e 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -37,7 +37,7 @@ typedef struct {
 } TabSHEET;
 
 //types of dialogs
-enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, COLBUTT, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
+enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTT, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
 	FILLRADIO, SYMRADIO, CHECKBOX, RADIO0, RADIO1, RADIO2, LTEXT, RTEXT, CTEXT, EDTEXT, 
 	RANGEINPUT, EDVAL1, INCDECVAL1, HSCROLL, VSCROLL, TXTHSP, ICON, GROUP, 
 	GROUPBOX, SHEET, ODBUTTON, LISTBOX1, TREEVIEW, LINEPAT, TEXTBOX, CHECKPIN, TRASH,
@@ -80,7 +80,7 @@ public:
 	virtual bool GetInt(int id, int *val) {return false;};
 	virtual bool SetCheck(int id, anyOutput *o, bool state) {return false;};
 	virtual bool GetCheck(int Id) {return bChecked;};
-	virtual bool GetText(int id, char *txt) {return false;};
+	virtual bool GetText(int id, char *txt, int size) {return false;};
 	virtual void MBtrack(MouseEvent *mev, anyOutput *o) {return;};
 	virtual void Activate(int id, bool active){return;};
 };
@@ -111,7 +111,7 @@ class DlgRoot:public tag_DlgObj {
 public:
 	anyOutput *CurrDisp;
 
-	DlgRoot(DlgInfo *tmpl);
+	DlgRoot(DlgInfo *tmpl, DataObj *d);
 	~DlgRoot();
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 	void DoPlot(anyOutput *o);
@@ -123,8 +123,9 @@ public:
 	bool SetCheck(int id, anyOutput *o, bool state);
 	bool GetCheck(int Id);
 	void Activate(int id, bool active);
-	bool GetText(int id, char *txt);
+	bool GetText(int id, char *txt, int size);
 	bool SetText(int id, char *txt);
+	bool SetValue(int id, double val);
 	bool TextStyle(int id, int style);
 	bool TextFont(int id, int font);
 	bool TextSize(int id, int size);
@@ -136,11 +137,13 @@ public:
 	anyOutput *GetOutputClass(){return CurrDisp;};
 
 private:
+	anyOutput *ParentOut;
 	int cDlgs, Result, cContinue;
+	DataObj *data;
 	Dialog *oldFocus, *oldDefault, *oldTabStop;
 	bool bActive;
 	GraphObj *c_go;
-	Dialog **tabstops;
+	Dialog **tabstops, *mrk_item;
 	DlgTmpl **dlg;
 	MouseEvent *mev;
 };
@@ -164,10 +167,11 @@ public:
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
-	bool GetText(int id, char *txt);
+	void MBtrack(MouseEvent *mev, anyOutput *o);
+	bool GetText(int id, char *txt, int size);
 
 private:
-	mLabel *cont;
+	TextFrame *cont;
 };
 
 class ArrowButton:public Dialog {
@@ -182,7 +186,6 @@ private:
 
 class ColorButton:public Dialog {
 public:
-	ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned long color);
 	ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, DWORD *color);
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
@@ -314,6 +317,7 @@ public:
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
 	void SetColor(int id, DWORD color);
+	void MBtrack(MouseEvent *mev, anyOutput *o);
 
 private:
 	char *txt;
@@ -330,7 +334,7 @@ public:
 	virtual bool Select(int x, int y, anyOutput *o);
 	bool GetValue(int id, double *val);
 	bool GetInt(int id, int *val);
-	bool GetText(int id, char *txt);
+	bool GetText(int id, char *txt, int size);
 	virtual void MBtrack(MouseEvent *mev, anyOutput *o);
 	virtual void Activate(int id, bool active);
 
@@ -340,7 +344,7 @@ private:
 
 class RangeInput:public InputText {
 public:
-	RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+	RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d);
 	~RangeInput();
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
@@ -454,12 +458,13 @@ private:
 
 class TabSheet:public Group {
 public:
-	TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET *sh);
+	TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET *sh, DataObj *d);
 	~TabSheet();
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
 
 private:
+	DataObj *data;
 	RECT rctab;
 	char *Text;
 };
@@ -485,7 +490,7 @@ public:
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
 	bool GetInt(int id, int *val);
-	bool GetText(int id, char *txt);
+	bool GetText(int id, char *txt, int size);
 	void MBtrack(MouseEvent *mev, anyOutput *o);
 
 private:
diff --git a/UtilObj.cpp b/UtilObj.cpp
index 0945652..2b39e4f 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -88,7 +88,7 @@ EditText::~EditText()
 bool
 EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
 {
-	char byte1, byte2, c, *tmp;
+	unsigned char byte1, byte2, c, *tmp;
 	POINT MyPos;
 	int i;
 
@@ -103,18 +103,18 @@ EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
 		}
 	Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
 	bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
-	if(text)length = strlen(text);
+	if(text)length = (int)strlen(text);
 	else length = 0;
-	if(text) tmp = (char *)realloc(text, length+2);
-	else tmp = (char *)calloc(2, sizeof(char));
+	if(text) tmp = (unsigned char *)realloc(text, length+2);
+	else tmp = (unsigned char *)calloc(2, sizeof(unsigned char));
 	if(!tmp) return false;
-	text = tmp;
+	text = (char*)tmp;
 	byte1 = byte2 = 0;
 	//replace mark by character if mark exists
 	if(hasMark()) {			//delete marked part of text
 			if(m1 > m2) Swap(m1, m2);
 			if(m2 >= (short int)strlen(text)) text[m1] = 0;
-			else strcpy(text+m1, text+m2);
+			else rlp_strcpy(text+m1, TMP_TXT_SIZE, text+m2);
 			CursorPos = m1;
 			m1 = m2 = -1;
 			}
@@ -130,9 +130,7 @@ EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
 	MyPos.x = Align & TXA_HRIGHT ? crb.x - 2 : loc.x + 2;
 	if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos, 
 		scroll_et == this ? scroll_dist : scroll_dist=0);
-	if(parent && text) {
-		((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' && ci != ')' ? this : 0L, 0L);
-		}
+	set_etracc();
 	return true;
 }
 
@@ -166,6 +164,7 @@ EditText::Update(int select, anyOutput *Out, POINT *MousePos)
 					}
 				else if(select ==1) Out->TextCursor(text, MyPos, NULL, &CursorPos, 
 					scroll_et == this ? scroll_dist : (scroll_dist=0)+2);
+				set_etracc();
 				}
 			break;
 		case 2:							//inactive spreadsheet cell
@@ -182,7 +181,11 @@ EditText::Update(int select, anyOutput *Out, POINT *MousePos)
 			if(text && text[0]) {
 				type = ET_VALUE;
 				Align = TXA_VCENTER | TXA_HRIGHT;
+#ifdef USE_WIN_SECURE
+				sscanf_s(text, "%lf", &Value);
+#else
 				sscanf(text, "%lf", &Value);
+#endif
 				}
 			break;
 		case 20:						//update value only
@@ -197,12 +200,17 @@ EditText::Redraw(anyOutput *Out, bool display)
 	RECT rc;
 	POINT MyPos;
 	char *txt, tmptxt[500];
-	int w, h, o_crbx;
+	int i, w, h, o_crbx;
 	bool b_clip = false;
 	anyOutput *opc;
 	anyResult cres;
+	POINT grid[3];
 
 	if(!parent && disp) Out = disp;
+	if((type & ET_NODRAW_EMPTY) == ET_NODRAW_EMPTY && CurrText != this){
+		type &= ~ET_NODRAW;
+		return true;
+		}
 	if(loc.x <1 || rb.x < 1 || loc.y <1 || rb.y <1) return false;
 	o_crbx = crb.x;			crb.x = rb.x;				crb.y = rb.y;
 	if (Out) {
@@ -211,9 +219,11 @@ EditText::Redraw(anyOutput *Out, bool display)
 		Out->TxtSet.Align = Align;		Out->TxtSet.ColTxt = TextCol;
 		Out->TxtSet.ColBg = bgLine->color;
 		if(text && text[0]) {
-			Out->oGetTextExtent(text, strlen(text), &w, &h);
-			if(CurrText == this) {
-				while((crb.x - loc.x) < (w+(h>>1))) crb.x += (rb.x - loc.x);
+			Out->oGetTextExtent(text, (int)strlen(text), &w, &h);
+			if(CurrText == this && parent && col >= 0) {
+				for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
+					crb.x += ((DataObj*)parent)->ri->GetWidth(i);
+					}
 				if(o_crbx > loc.x && o_crbx > crb.x && o_crbx < 4000) crb.x = o_crbx;
 				}
 			else if((crb.x - loc.x) < (w+(h>>1))) b_clip = true;
@@ -223,8 +233,12 @@ EditText::Redraw(anyOutput *Out, bool display)
 		rc.top = loc.y+1;			rc.bottom = crb.y-2;
 		Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
 		if((!text || !text[0]) && (type & 0xff) == ET_VALUE){
+#ifdef USE_WIN_SECURE
+			sprintf_s(tmptxt, 500, "%g", Value);
+#else
 			sprintf(tmptxt, "%g", Value);
-			if(text = (char*)realloc(text, strlen(tmptxt)+2)) strcpy(text, tmptxt);
+#endif
+			if(text = (char*)realloc(text, strlen(tmptxt)+2)) rlp_strcpy(text, 500, tmptxt);
 			CursorPos = 0;
 			}
 		if(ftext) free(ftext);		ftext = 0L;
@@ -236,30 +250,42 @@ EditText::Redraw(anyOutput *Out, bool display)
 				switch (cres.type) {
 				case ET_VALUE:
 					Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
-					b_clip = false;				strcpy(tmptxt, cres.text);
+					b_clip = false;				rlp_strcpy(tmptxt, 500, cres.text);
 					fit_num_rect(Out, rb.x - loc.x, tmptxt);
 					Int2Nat(tmptxt);			break;
 				case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
 				case ET_TEXT:
 					Out->TxtSet.Align = cres.type == ET_TEXT ? 
 						TXA_HLEFT | TXA_VCENTER : TXA_HRIGHT | TXA_VCENTER;
-					if(ftext) free (ftext);		ftext = 0L;
-					if(cres.text) ftext = strdup(cres.text);
-					if(cres.text && strlen(cres.text)<sizeof(tmptxt)) 
-						strcpy(tmptxt, cres.text[0] != '\'' ? cres.text : cres.text +1);
-					else if(cres.text) sprintf(tmptxt,"#SIZE");
+					i = (int)strlen(cres.text)+2;
+					if(ftext = (char*)realloc(ftext, i > 20 ? i : 20))rlp_strcpy(ftext, i, cres.text);
+					if(cres.text && i < sizeof(tmptxt)) 
+						rlp_strcpy(tmptxt, 500, cres.text[0] != '\'' ? cres.text : cres.text +1);
+					else if(cres.text)rlp_strcpy(tmptxt, 500, "#SIZE");
 					else tmptxt[0] = 0;			
-					Out->oGetTextExtent(tmptxt, strlen(tmptxt), &w, &h);
+					Out->oGetTextExtent(tmptxt, (int)strlen(tmptxt), &w, &h);
 					b_clip = (crb.x - loc.x) < (w+(h>>1)) ? true : false;
 					break;
 				case ET_ERROR:
-					strcpy(tmptxt, "#ERROR");	break;
+					rlp_strcpy(tmptxt, 500, "#ERROR");	break;
 				default: 
-					strcpy(tmptxt, "#VALUE");	break;
+					rlp_strcpy(tmptxt, 500, "#VALUE");	break;
 					}
 				txt = tmptxt;
 				}
 			else txt = text;
+			if(b_clip && parent && col >= 0 && row >=0) {
+				Out->oGetTextExtent(txt, (int)strlen(txt), &w, &h);
+				for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
+					if(((DataObj*)parent)->isEmpty(row, i)) {
+						crb.x += ((DataObj*)parent)->ri->GetWidth(i);
+						((DataObj*)parent)->etRows[row][i]->type |= ET_NODRAW;
+						}
+					else break;
+					}
+				if((crb.x - loc.x) >= (w+(h>>1))) b_clip = false;
+				else rc.right = crb.x;
+				}
 			MyPos.y = (loc.y+rb.y)>>1;
 			if(Out->TxtSet.Align & TXA_HRIGHT) {	//right justified text
 				MyPos.x = crb.x-4;
@@ -273,7 +299,7 @@ EditText::Redraw(anyOutput *Out, bool display)
 					}
 				opc->Erase(bgFill->color);
 				opc->SetTextSpec(&Out->TxtSet);		opc->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
-				opc->oTextOut(4,(rb.y-loc.y)>>1, txt, strlen(txt));
+				opc->oTextOut(4,(rb.y-loc.y)>>1, txt, (int)strlen(txt));
 				if(!parent && CursorPos) {
 					Out->oGetTextExtent(txt, CursorPos, &w, &h);
 					while((scroll_dist + w)>(rc.right-rc.left-10)) scroll_dist -=10;
@@ -293,15 +319,19 @@ EditText::Redraw(anyOutput *Out, bool display)
 					}
 				scroll_dist = 0;
 				Out->oTextOut(MyPos.x, MyPos.y, txt, 0);
+				if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
+					rc.left = mx1;		rc.right = mx2;
+					Out->CopyBitmap(mx1, rc.top, Out, mx1, rc.top, mx2-mx1, rc.bottom-rc.top, true);
+					Out->MrkMode = MRK_NONE;
+					}
 				}
 			}
+		Out->SetLine((LineDEF*)&GrayLine);
+		grid[0].x = loc.x;					grid[0].y = grid[1].y = crb.y-1;
+		grid[1].x = grid[2].x = crb.x-1;	grid[2].y = loc.y-1;
+		Out->oPolyline(grid, 3, 0L);
 		if(display) {
 			if(!(Out->UpdateRect(&rc, false))) return false;
-			if(hasMark() && mx1 > loc.x && mx2 < rb.x) {
-				rc.left = mx1;		rc.right = mx2;
-				Out->UpdateRect(&rc, true);
-				Out->MrkMode = MRK_NONE;
-				}
 			}
 		return true;
 	}
@@ -371,6 +401,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			return true;
 		case CMD_SETFONT:
 			if (!text || !text[0]) return false;
+			if(Out) Undo.SetDisp(Out);
 			type = ET_TEXT;
 			if(hasMark()) {
 				Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
@@ -398,15 +429,16 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				for( ; w < k; w++) TmpTxt[i++] = text[w];
 				for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
 				for( ; TmpTxt[i++] = text[w]; w++);
-				m1 += (w = strlen(tag1));	m2 += w;	CursorPos += w;
+				m1 += (w = (int)strlen(tag1));	m2 += w;	CursorPos += w;
 				CleanTags(TmpTxt, &m1, &m2, &CursorPos);
-				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
+				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
 				Command(CMD_REDRAW, Out, 0L);
 				return true;
 				}
 			return false;
 		case CMD_SETSTYLE:
 			if (!text || !text[0]) return false;
+			if(Out) Undo.SetDisp(Out);
 			type = ET_TEXT;
 			if(hasMark()) {
 				Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
@@ -446,9 +478,9 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				for( ; w < k; w++) TmpTxt[i++] = text[w];
 				for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
 				for( ; TmpTxt[i++] = text[w]; w++);
-				m1 += (w = strlen(tag1));	m2 += w;	CursorPos += w;
+				m1 += (w = (int)strlen(tag1));	m2 += w;	CursorPos += w;
 				CleanTags(TmpTxt, &m1, &m2, &CursorPos);
-				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
+				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
 				Command(CMD_REDRAW, Out, 0L);
 				return true;
 				}
@@ -462,12 +494,12 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				for(k = 0; tag1[k] && tag1[k] == text[k]; k++);
 				if(tag1[k]!=';') k = 0;
 				for(i = 0; i < CursorPos && text[i]; i++) TmpTxt[i] = text[i];
-				j = i + sprintf(TmpTxt+i, "%s", tag1+k);
-				if(text[i]) sprintf(TmpTxt+j, "%s", text+i);
-				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
-				CursorPos += strlen(tag1+k);
-				Out->Focus();
-				Update(1, Out, 0L);
+				j = i + rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, tag1+k);
+				if(text[i]) j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, text+i);
+				if(text = (char*)realloc(text, j+2 )) rlp_strcpy(text, j+2, TmpTxt);
+				CursorPos += (int)strlen(tag1+k);
+				Out->Focus();					Update(1, Out, 0L);
+				set_etracc();
 				}
 			return true;
 		case CMD_BACKSP:
@@ -494,21 +526,21 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				if (!text || !text[0]) return false;
 				if(m1 > m2) Swap(m1, m2);
 				if(m2 >= (short int)strlen(text)) text[m1] = 0;
-				else strcpy(text+m1, text+m2);
-				CursorPos = m1;
-				m1 = m2 = -1;
+				else rlp_strcpy(text+m1, (int)strlen(text)+m1, text+m2);
+				CursorPos = m1;						m1 = m2 = -1;
+				if(!text[0]) {
+					type = ET_UNKNOWN;	CursorPos = 0;
+					}
 				if(Out) Redraw(Out, (bRet = true));
 				}
 			else if(text[CursorPos]) {
-				strcpy(text + CursorPos, text + CursorPos + 1);
+				rlp_strcpy(text + CursorPos, (int)strlen(text + CursorPos), text + CursorPos + 1);
 				if(!text || !text[0]) {
 					type = ET_UNKNOWN;	CursorPos = 0;
 					}
 				if(Out)Redraw(Out, (bRet = true));
 				}
-			if(parent) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
+			set_etracc();
 			if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
 				scroll_et == this ? scroll_dist : scroll_dist=0);
 			return bRet;
@@ -528,7 +560,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 						}
 					return false;
 					}
-				CopyText(text, strlen(text));
+				CopyText(text, (int)strlen(text));
 				if(Out)Out->UpdateRect(&rMark, true);
 				return false;
 				}
@@ -538,9 +570,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
 				for(i = 0; pt[i] > 0x20 && i < 81; i++) this->AddChar(pt[i], 0L, 0L);
 				if(Out) Redraw(Out, true);				free(pt);
-				if(parent && text) {
-					((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-					}
+				set_etracc();
 				if(i) return true;
 				}
 			return false;
@@ -550,15 +580,11 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			else if(text[CursorPos]){
 				m1 = CursorPos;	m2 = CursorPos+1;
 				}
-			if(parent && text) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
+			set_etracc();
 			if(text[CursorPos]) CursorPos++;
 			else return false;
 		case CMD_SHIFTLEFT:
-			if(parent && text) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
+			set_etracc();
 			if (!(CursorPos)) return false;
 		case CMD_REDRAW:
 			if(cmd == CMD_SHIFTLEFT) {
@@ -584,15 +610,12 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				Out->oGetTextExtent(text+m1, m2-m1, &w, &h);
 				mx2 = mx1 + w;
 				}
-			HideTextCursor();		Redraw(Out, true);
+			HideTextCursor();				Redraw(Out, true);
 			Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
 				scroll_et == this ? scroll_dist : scroll_dist=0);
 			return true;
 		case CMD_CURRLEFT:
-			m1 = m2 = -1;
-			if(parent && text) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
+			m1 = m2 = -1;					set_etracc();
 			if(CursorPos >0) {
 				CursorPos--;
 				if(Redraw(Out, true) && Out->TextCursor(text, MyPos, (POINT *) NULL,
@@ -607,10 +630,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				}
 			return false;
 		case CMD_CURRIGHT:
-			m1 = m2 = -1;
-			if(parent && text) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
+			m1 = m2 = -1;					set_etracc();
 			if(text[CursorPos]){
 				CursorPos++;
 				if(Redraw(Out, true) && Out->TextCursor(text, MyPos, (POINT *) NULL,
@@ -629,21 +649,18 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			Redraw(Out, true);
 			return true;
 		case CMD_POS_FIRST:		case CMD_POS_LAST:
-			if(parent && text) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
-			CursorPos = (cmd == CMD_POS_LAST && text && text[0]) ? strlen(text) : 0;
-			m1 = m2 = -1;
-			Redraw(Out, true);
+			CursorPos = (cmd == CMD_POS_LAST && text && text[0]) ? (int)strlen(text) : 0;
+			m1 = m2 = -1;		Redraw(Out, true);
 			Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
 				scroll_et == this ? scroll_dist : scroll_dist=0);
+			set_etracc();
 			return true;
 		case CMD_CURRDOWN:		case CMD_CURRUP:
 			if (data_obj) {
 			//the following calculation of the cursor position is crude
             //it is based on a aspect of 2:1 for digits
 				if(Align & TXA_HRIGHT)		//right justified text
-					MyPos.x = rb.x-4-((rb.y-loc.y-4)*(strlen(text)-CursorPos))/2;
+					MyPos.x = rb.x-4-((rb.y-loc.y-4)*((long)strlen(text)-CursorPos))/2;
 				else MyPos.x = loc.x+4+((rb.y-loc.y-4)*CursorPos)/2;
 				MyPos.y = (cmd == CMD_CURRUP) ? loc.y-2 : rb.y+2;
 				if(MyPos.x < loc.x) MyPos.x = loc.x +4;
@@ -658,13 +675,13 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			if(!text || !text[0]) return false;
 			if(mev->x <loc.x || mev->x >crb.x || mev->y <loc.y || mev->y >rb.y)return false;
 			if(mev->Action == MOUSE_LBDOWN) {
-				m1 = m2 = -1;
+				m1 = m2 = -1;//					set_etracc();
 				return true;
 				}
 			if(mev->Action == MOUSE_LBDOUBLECLICK) {
 				rMark.top = loc.y+1;			rMark.bottom = rb.y-2;
-				if(!Out->oGetTextExtent(text, strlen(text), &w, &h)) return false;
-				m1 = 0;							m2 = strlen(text);
+				if(!Out->oGetTextExtent(text, (int)strlen(text), &w, &h)) return false;
+				m1 = 0;							m2 = (int)strlen(text);
 				if(Align & TXA_HRIGHT) {		//right justfied text
 					rMark.right = crb.x -4;		rMark.left = crb.x - w - 4;
 					}
@@ -672,10 +689,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 					rMark.left = loc.x +4;		rMark.right = rMark.left +w;
 					}
 				mx1 = rMark.left;				mx2 = rMark.right;
-				Redraw(Out, true);
-				if(parent && text) {
-					((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-					}
+				Redraw(Out, true);				set_etracc();
 				return true;
 				}
 			MyPos.x = Align & TXA_HRIGHT ? mev->x + 4 : mev->x - 4;
@@ -684,7 +698,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			j = Out->CalcCursorPos(text, Align & TXA_HRIGHT ? crb :loc, &MyPos);
 			if(j == m1 || j == m2) return true;
 			if(Align & TXA_HRIGHT) {			//right justfied text
-				if((i = strlen(text)-j)){
+				if((i = (int)strlen(text)-j)){
 					if(!Out->oGetTextExtent(text+j, i, &w, &h)) return false;
 					w = crb.x - w - 4;
 					}
@@ -706,7 +720,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				rMark.top = loc.y+1;				rMark.bottom = rb.y-2;
 				if(rMark.right < crb.x && rMark.right > loc.x &&
 					rMark.left > loc.x && rMark.left < crb.x)
-					Out->UpdateRect(&rMark,true);
+					Redraw(Out, true);
 				}
 			if(hasMark() && parent)
 				//remove range-mark of data 
@@ -766,28 +780,29 @@ EditText::GetText(char *tx, int size, bool bTranslate)
 		else t = text;
 		}
 	else if(bTranslate) {
-		GetResult(&res, false);					TranslateResult(&res);
+		GetResult(&res, false);						TranslateResult(&res);
 		switch (res.type) {
 		case ET_VALUE:
-			strcpy(tmp_txt, res.text);			t = tmp_txt;
-			Int2Nat(tmp_txt);					break;
-		case ET_BOOL:		case ET_DATE:		case ET_TIME:	
+			rlp_strcpy(tmp_txt, 40, res.text);		t = tmp_txt;
+			Int2Nat(tmp_txt);						break;
+		case ET_BOOL:		case ET_DATE:			case ET_TIME:	
 		case ET_DATETIME:	case ET_TEXT:
-			t = res.text;						break;
+			t = res.text;							break;
 		default:
-			t = 0L;								break;
+			t = 0L;									break;
 			}
 		}
 	else if(text && text[0]) t = (text[0] =='\'' && text[1]) ? text+1 : text;
 	if(t) {
-		if((int)strlen(t) < size) strcpy(tx, t);
-		else {
-			memcpy(tx, text, size-1);			tx[size-1] = 0;
-			}
+		rlp_strcpy(tx, size, t);
 		return true;
 		}
 	else if((type & 0xff) == ET_VALUE) {
+#ifdef USE_WIN_SECURE
+		if(text = (char*)realloc(text, 20)) sprintf_s(text, 20, "%g", Value);
+#else
 		if(text = (char*)realloc(text, 20)) sprintf(text, "%g", Value);
+#endif
 		if(text && text[0]) return(GetText(tx, size, false));
 		}
 	return false;
@@ -863,9 +878,11 @@ EditText::SetValue(double v)
 bool
 EditText::SetText(char *t)
 {
+	int cb;
+
 	Value = 0.0;	type = ET_UNKNOWN;
 	bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
-	if(t && t[0] && (text = (char*)realloc(text, strlen(t)+2))) strcpy(text, t);
+	if(t && t[0] && (text = (char*)realloc(text, cb = (int)(strlen(t)+2)))) rlp_strcpy(text, cb, t);
 	else if (text) text[0] = 0;
 	return false;
 }
@@ -896,29 +913,36 @@ EditText::isFormula()
 void
 EditText::FindType()
 {
-	int i, c1, c2, c3, c4;
+	int i, c1, c2, c3, c4, c5;
 
 	if(!text || !text[0]) {
 		Align = TXA_VCENTER | TXA_HRIGHT;
-		if ((type && 0xff) == ET_VALUE) type = ET_VALUE;
-		else type = ET_UNKNOWN;
+		if ((type & 0xff) == ET_VALUE) type = ET_VALUE;
+		else type = ET_UNKNOWN | ET_EMPTY;
 		return;
 		}
 	if(text[0] == '=') {
 		Align = TXA_VCENTER | TXA_HRIGHT;
 		type = ET_FORMULA;
 		}
-	else if(isdigit(text[0]) || ((text[0] == '-' ) || text[0] == '.' 
-		|| text[0] == defs.DecPoint[0]) && (isdigit(text[1]))) {
-		for(i = c1 = c2 = c3 = c4 = 0; text[i]; i++) {
+	else if(text[0] > 31 && isdigit(text[0]) || ((text[0] == '-' ) || text[0] == '.' 
+		|| text[0] == defs.DecPoint[0]) && text[1]>31 && (isdigit(text[1]))) {
+		for(i = c1 = c2 = c3 = c4 = c5 = 0; text[i]; i++) {
 			switch(text[i]) {
 			case '.':		c1++;		break;
 			case '-':		c2++;		break;
 			case '/':		c3++;		break;
 			case ':':		c4++;		break;
+			case 'e':		break;
+			case 'E':		break;
+			default:		if(isalpha(text[i])) c5++;
 				}
 			}
-		if(c1 < 2 && c2 < 2 && !c3  && !c4 && Txt2Flt(text, &Value)) {
+		if(c5 > 0){
+			Align = TXA_VCENTER | TXA_HLEFT;
+			type = ET_TEXT;
+			}
+		else if(c1 < 2 && c2 < 2 && !c3  && !c4 && Txt2Flt(text, &Value)) {
 			Align = TXA_VCENTER | TXA_HRIGHT;
 			type = ET_VALUE;
 			}
@@ -963,6 +987,27 @@ EditText::FindType()
 		}
 }
 
+void
+EditText::set_etracc()
+{
+	int i;
+	bool accept_range;
+	anyResult *res;
+
+	if(parent) {
+		if(hasMark()) i = m1 < m2 ? m1 : m2;
+		else i = CursorPos;
+		accept_range = (i && text && text[0] == '=' && text[i-1]!=')'
+			&& text[i-1] > 31 && !(isdigit(text[i-1]) || isalpha(text[i-1])));
+		if(accept_range) {
+			res = do_formula((DataObj*)parent, text+1);
+			if(res->type != ET_ERROR) accept_range = false;
+			((DataObj*)parent)->Command(CMD_CLEAR_ERROR, 0L, 0L);
+			}
+		((DataObj*)parent)->Command(CMD_ETRACC, accept_range ? this : 0L, 0L);
+		}
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // output formated text - style and font changes
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1002,11 +1047,16 @@ static tag_info tags[] = {
 
 static int font_buff[256];
 static unsigned font_idx=0;
+fmtText::fmtText()
+{
+	src=0L;	split_text=0L;		n_split=0;
+	pos.x = pos.y = 0;			flags =0x0;
+}
 
 fmtText::fmtText(anyOutput *o, int x, int y, char *txt)
 {
-	if(txt && txt[0]) src=strdup(txt);
-	else src=0L;	split_text=0L;	n_split=0;
+	if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+	else src=0L;	split_text=0L;	n_split=0;	flags = 0x0;
 	pos.x = x;	pos.y = y;	if(src)Parse();
 	if(o) DrawText(o);
 }
@@ -1025,9 +1075,9 @@ fmtText::StyleAt(int idx, TextDEF *txt_def, int *style, int *font)
 	if(!src || !split_text || (idx > (int)strlen(src))) return false;
 	memcpy(&td, txt_def, sizeof(TextDEF));
 	for(i = j = 0; i < n_split; i++) {
-		if((n=split_text[i].tag) >= 0  && SetTextDef(&td, n)) j += strlen(tags[n].tag);
+		if((n=split_text[i].tag) >= 0  && SetTextDef(&td, n)) j += (int)strlen(tags[n].tag);
 		if(j > idx) break;
-		if(split_text[i].txt && split_text[i].txt[0]) j += strlen(split_text[i].txt);
+		if(split_text[i].txt && split_text[i].txt[0]) j += (int)strlen(split_text[i].txt);
 		if(j >= idx) break;
 		}
 	if(style) *style = td.Style;		if(font) *font = td.Font;
@@ -1053,7 +1103,7 @@ fmtText::leftTag(char *txt, int cb)
 	int i, j, k;
 
 	for(i = 0; tags[i].tag; i++) {
-		for(j = 0, k=strlen(tags[i].tag)-1; tags[i].tag[j] && k <=cb; j++, k--) {
+		for(j = 0, k=(int)strlen(tags[i].tag)-1; tags[i].tag[j] && k <=cb; j++, k--) {
 			if(tags[i].tag[j] != txt[cb-k]) break;
 			}
 		if(!tags[i].tag[j]) return i;
@@ -1068,7 +1118,7 @@ fmtText::cur_right(int *pos)
 
 	if(!src || !pos || !src[*pos]) return;
 	if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
-		*pos += strlen(tags[n].tag);
+		*pos += (int)strlen(tags[n].tag);
 		cur_right(pos);
 		}
 	else (*pos)++;
@@ -1082,7 +1132,7 @@ fmtText::cur_left(int *pos)
 	if(!src || !pos || !(*pos)) return;
 	(*pos)--;
 	while (src[*pos] == '>' && (n=leftTag(src, *pos)) >= 0) {
-		*pos -= strlen(tags[n].tag);
+		*pos -= (int)strlen(tags[n].tag);
 		}
 }
 
@@ -1093,16 +1143,17 @@ fmtText::oGetTextExtent(anyOutput *o, int *width, int *height, int cb)
 	int i, n, l, l1, w, w1, h, h1;
 
 	if(!o || !width || !height) return false;
-	if(!cb) cb = strlen(src);
+	if(!src || !src[0]) return false;
+	if(!cb) cb = (int)strlen(src);
 	if(!split_text) return o->oGetTextExtent(src, cb, width, height);
 	memcpy(&td1, &o->TxtSet, sizeof(TextDEF));	memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
 	for(i = w = h = l = l1 = 0; i < n_split; i++){
 		if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
 			o->SetTextSpec(&td2);
-			l += strlen(tags[n].tag);
+			l += (int)strlen(tags[n].tag);
 			}
 		if(split_text[i].txt && split_text[i].txt[0]){
-			l1 = l;		l += strlen(split_text[i].txt);
+			l1 = l;		l += (int)strlen(split_text[i].txt);
 			if (l1 >= cb) break;
 			o->oGetTextExtent(split_text[i].txt, l >= cb ? cb-l1 : 0, &w1, &h1);
 			w += w1;	h = h1 > h ? h1 : h;
@@ -1131,7 +1182,8 @@ fmtText::SetText(anyOutput *o, char *txt, int *px, int *py)
 		for(i = 0; i < n_split; i++) if(split_text[i].txt) free(split_text[i].txt);
 		free(split_text);		split_text = 0L;	n_split = 0;
 		}
-	if(txt && txt[0]) src=strdup(txt);		if(src)Parse();
+	if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+	if(src)Parse();
 	if(o) DrawText(o);
 }
 
@@ -1166,7 +1218,7 @@ fmtText::Parse()
 	int i, li, j, n;
 	char *tmp;
 
-	if(!src || !(tmp = strdup(src))) return false;
+	if((flags & 0x01) || !src || !(tmp = (char*)memdup(src, (int)strlen(src)+1, 0))) return false;
 	for(i = li = 0; src[i]; i++) {
 		if(src[i] == '<' && (n=rightTag(src, i))>=0) {
 			if(split_text) {				//more tags in text
@@ -1174,8 +1226,8 @@ fmtText::Parse()
 					free(tmp);					return false;
 					}
 				for(j = li; j < i; j++) tmp[j-li]= src[j];	tmp[j-li]=0;
-				split_text[n_split-1].txt = strdup(tmp);
-				i += strlen(tags[n].tag);	split_text[n_split].tag = n;
+				split_text[n_split-1].txt = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+				i += (int)strlen(tags[n].tag);	split_text[n_split].tag = n;
 				split_text[n_split++].txt = 0L;
 				}
 			else {							//first tag of text
@@ -1183,14 +1235,16 @@ fmtText::Parse()
 					free(tmp);					return false;
 					}
 				for(j = 0; j < i; j++) tmp[j]= src[j];	tmp[j]=0;
-				split_text[0].tag = -1;		split_text[0].txt = strdup(tmp);
-				i += strlen(tags[n].tag);	split_text[1].tag = n;
+				split_text[0].tag = -1;		
+				split_text[0].txt = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+				i += (int)strlen(tags[n].tag);	split_text[1].tag = n;
 				n_split = 2;
 				}
 			li = i;							i--;
 			}
 		}
-	if(split_text && n_split && li < i && src[li]) split_text[n_split-1].txt = strdup(src+li);
+	if(split_text && n_split && li < i && src[li]) 
+		split_text[n_split-1].txt = (char*)memdup(src+li, (int)strlen((char*)src+li)+1,0);
 	free(tmp);
 	return true;
 }
@@ -1318,7 +1372,100 @@ fmtText::DrawFormatted(anyOutput *o)
 			x = iround(fx += (w*csi));		y = iround(fy -= (w*si));
 			}
 		}
-	o->SetTextSpec(&td1);
+}
+
+void
+fmtText::EditMode(bool bEdit)
+{
+	if(bEdit) flags |= 0x01;
+	else flags &= ~(0x01);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// manage formats and style of a spreadsheet range
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RangeInfo::RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next)
+{
+	r_type = sel;		col_width = cw;		row_height = rh;	first_width = fw;
+	ri_next = next;		ar = 0L;
+}
+
+RangeInfo::RangeInfo(int sel, char *range, RangeInfo *next)
+{
+	r_type = sel;		ri_next = next;
+	if(range && range[0]) {
+		ar = new AccRange(range);
+		}
+	else ar = 0L;
+}
+
+RangeInfo::~RangeInfo()
+{
+	if(ar) delete ar;
+}
+
+int
+RangeInfo::SetWidth(int w)
+{
+	if(r_type == 0 || r_type == 1) return col_width = w;
+	else if (ri_next) return ri_next->SetWidth(w);
+	return w;
+}
+
+int
+RangeInfo::SetDefWidth(int w)
+{
+	if(r_type == 0) return col_width = w;
+	else if (ri_next) return ri_next->SetDefWidth(w);
+	return w;
+}
+
+int
+RangeInfo::SetHeight(int h)
+{
+	if(r_type == 0) return row_height = h;
+	else if (ri_next) return ri_next->SetHeight(h);
+	return h;
+}
+
+int
+RangeInfo::SetFirstWidth(int w)
+{
+	if(r_type == 0) return first_width = w;
+	else if (ri_next) return ri_next->SetFirstWidth(w);
+	return w;
+}
+
+int
+RangeInfo::GetWidth(int col)
+{
+	int r, c;
+
+	if(r_type == 0) return col_width;
+	else if (ar && r_type == 1){
+		ar->GetFirst(&c, &r);
+		while(ar->NextCol(&c)) {
+			if(c == col) return col_width;
+			}
+		}
+	if(ri_next) return ri_next->GetWidth(col);
+	return 0;
+}
+
+int
+RangeInfo::GetHeight(int row)
+{
+	if(r_type == 0) return row_height;
+	else if (ri_next) return ri_next->GetHeight(row);
+	return row_height;
+}
+
+int
+RangeInfo::GetFirstWidth()
+{
+	if(r_type == 0) return first_width;
+	else if (ri_next) return ri_next->GetFirstWidth();
+	return first_width;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1328,11 +1475,13 @@ DataObj::DataObj()
 {
 	cRows = cCols = 0;
 	etRows = 0L;
+	ri = new RangeInfo(0, 1, 1, 1, 0L);
 }
 
 DataObj::~DataObj()
 {
 	FlushData();
+	delete ri;
 }
 
 bool
@@ -1408,6 +1557,17 @@ DataObj::GetSize(int *width, int *height)
 	return true;
 }
 
+bool
+DataObj::isEmpty(int row, int col)
+{
+	if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+	if(etRows[row][col]) {
+		if((etRows[row][col]->type & 0xff) == ET_UNKNOWN)etRows[row][col]->Update(20, 0L, 0L);
+		if((etRows[row][col]->type & ET_EMPTY) == ET_EMPTY) return true;
+		}
+	return false;
+}
+
 void
 DataObj::FlushData()
 {
@@ -1475,7 +1635,10 @@ StrData::StrData(DataObj *par, RECT *rc)
 			if(!(str_data[r1] = (char**)malloc((w+1) * sizeof(char*)))) break;
 			for(c1 = 0, c2= drc.left; c1 <= w; c1++, c2++) {
 				tx = src->GetTextPtr(r2, c2);
-				str_data[r1][c1] = tx && *tx && *tx[0] ? strdup(*tx) : 0L;
+				if(tx && *tx && *tx[0]) {
+					str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
+					}
+				else str_data[r1][c1] = 0L;
 				}
 			}
 		}
@@ -1485,7 +1648,10 @@ StrData::StrData(DataObj *par, RECT *rc)
 			if(!(str_data[r1] = (char**)malloc(pw * sizeof(char*)))) break;
 			for(c1 = 0; c1 < pw; c1++) {
 				tx = src->GetTextPtr(r1, c1);
-				str_data[r1][c1] = tx && *tx && *tx[0] ? strdup(*tx) : 0L;
+				if(tx && *tx && *tx[0]) {
+					str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
+					}
+				else str_data[r1][c1] = 0L;
 				}
 			}
 		drc.right = pw-1;		drc.bottom = ph-1;
@@ -1543,7 +1709,7 @@ notary::~notary()
 	FreeStack();
 }
 
-unsigned long
+int
 notary::RegisterGO(GraphObj *go)
 {
 	int i, j;
@@ -1565,27 +1731,27 @@ notary::RegisterGO(GraphObj *go)
 		}
 	if(gObs[i] && gObs[i][j] && gObs[i][j] == go) {
 		NextRegGO = ((i << 13) | j);
-		return (unsigned long)i*0x2000L+j+1;
+		return i*0x2000+j+1;
 		}
 	if(gObs && gObs[0]) {
 		for(i = 0; i < 0x2000; i++) {
 			for(j = 0; j < 0x2000L; j++) {
 				if(gObs[i][j] == go) {
 					NextRegGO = ((i << 13) | j);
-					return (unsigned long)i*0x2000L+j+1;
+					return i*0x2000+j+1;
 					}
 				if(!gObs[i][j]) {
 					gObs[i][j] = go;
 					NextRegGO = ((i << 13) | j);
-					return (unsigned long)i*0x2000L+j+1;
+					return i*0x2000+j+1;
 					}
 				}
 			if(i < 0x1fffL && !gObs[i+1])
 				gObs[i+1] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
-			if(i < 0x1fffL && !gObs[i+1]) return 0L;
+			if(i < 0x1fff && !gObs[i+1]) return 0;
 			}
 		}
-	return 0L;
+	return 0;
 }
 
 void
@@ -1618,7 +1784,7 @@ notary::AddRegGO(GraphObj *go)
 }
 
 bool
-notary::PushGO(unsigned long id, GraphObj *go)
+notary::PushGO(unsigned int id, GraphObj *go)
 {
 	int i, j;
 
@@ -1661,7 +1827,7 @@ notary::PushGO(unsigned long id, GraphObj *go)
 }
 
 GraphObj *
-notary::PopGO(unsigned long id)
+notary::PopGO(unsigned int id)
 {
 	int i, j;
 	GraphObj *go;
@@ -1719,7 +1885,11 @@ notary::FreeStack()
 			}
 		free(goStack);
 		if(k){
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d objects deleted\nby notary", k);
+#else
 			sprintf(TmpTxt,"%d objects deleted\nby notary", k);
+#endif
 			ErrorBox(TmpTxt);
 			}
 		}
@@ -1733,7 +1903,7 @@ AccRange::AccRange(char *asc)
 {
 	int i, j, l;
 
-	if(asc && *asc && (l=strlen(asc)) >1){
+	if(asc && *asc && (l=(int)strlen(asc)) >1){
 		txt = (char *)malloc(l+2);
 		for(i = j = 0; i< (int)strlen(asc); i++)
 			if(asc[i] > 32) txt[j++] = asc[i];
@@ -1848,7 +2018,7 @@ AccRange::Parse(int start)
 	if(!txt[i]) return false;
 	step = x1 = y1 = x2 = y2 = 0;
 	v = &x1;
-	for (l=strlen(txt)+1 ; i < l; i++) {
+	for (l=(int)strlen(txt)+1 ; i < l; i++) {
 		if(txt[i] == '$') i++;
 		switch(step) {
 		case 0:
@@ -1903,13 +2073,174 @@ AccRange::Parse(int start)
 	return false;
 }
 
+//get a description for the current range from the data object
+char *
+AccRange::RangeDesc(void *d, int style)
+{
+	anyResult res;
+	int cb;
+	char *desc;
+
+	if(!d || !txt || !Reset())return 0L;
+	((DataObj*)d)->GetResult(&res, y1, x1, false);
+	if(res.type == ET_TEXT) {
+		if(res.text && res.text[0])
+			return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
+		else return 0L;
+		}
+	if(!(desc = (char*)malloc(40*sizeof(char))))return 0L;
+	if(x1 == x2) {
+		if(style == 1) cb = rlp_strcpy(desc, 40, "Col. ");
+		else if(style == 2) cb = rlp_strcpy(desc, 40, "Column ");
+		else goto rdesc_err;
+		rlp_strcpy(desc+cb, 40-cb, Int2ColLabel(x1, true));
+		return desc;
+		}
+	else if(y1 == y2) {
+#ifdef USE_WIN_SECURE
+		sprintf_s(desc, 40, "Row %d", y1+1);
+#else
+		sprintf(desc, "Row %d", y1+1);
+#endif
+		return desc;
+		}
+rdesc_err:
+	free(desc);
+	return 0L;
+}
+
+//---------------------------------------------------------------------------
+// Use the Delauney triangulation to create a 3D mesh of dispersed data
+//---------------------------------------------------------------------------
+void
+Triangle::SetRect()
+{
+	int i, i2;
+	double dy1, dy2, dx, dy;
+	double m1, m2, mx1, mx2, my1, my2;
+
+	//setup bounding rectangle
+	rc.Xmin = rc.Xmax = pt[0].fx;	rc.Ymin = rc.Ymax = pt[0].fy;
+	for(i = 1; i < 3; i++) {
+		if(pt[i].fx < rc.Xmin) rc.Xmin = pt[i].fx;
+		if(pt[i].fx > rc.Xmax) rc.Xmax = pt[i].fx;
+		if(pt[i].fy < rc.Ymin) rc.Ymin = pt[i].fy;
+		if(pt[i].fy > rc.Ymax) rc.Ymax = pt[i].fy;
+		}
+	//get three line equations in 2D
+	for(i = 0; i < 3; i++) {
+		i2 = (i+1)%3;
+		ld[i].fx = pt[i].fy;
+		if(pt[i].fx != pt[i2].fx) {
+			ld[i].fy = (pt[i2].fy - pt[i].fy) / (pt[i2].fx - pt[i].fx);
+			}
+		else ld[i].fy = HUGE_VAL;
+		}
+	//close polygon
+	pt[3].fx = pt[0].fx;	pt[3].fy = pt[0].fy;	pt[3].fz = pt[0].fz;
+	//circumcricle
+	dy1 = fabs(pt[0].fy - pt[1].fy);			dy2 = fabs(pt[1].fy - pt[2].fy);
+	m1 = (pt[0].fx - pt[1].fx)/(pt[1].fy - pt[0].fy);
+	m2 = (pt[1].fx - pt[2].fx)/(pt[2].fy - pt[1].fy);
+	mx1 = (pt[0].fx + pt[1].fx)/2.0;			my1 = (pt[0].fy + pt[1].fy)/2.0;
+	mx2 = (pt[1].fx + pt[2].fx)/2.0;			my2 = (pt[1].fy + pt[2].fy)/2.0;
+	if(dy1 < 1.0e-16 && dy2 < 1.0e-16) {
+		cy = (pt[0].fy + pt[1].fy + pt[2].fy)/3.0;
+		cx = (pt[0].fx + pt[1].fx + pt[2].fx)/3.0;
+		r2 = 0.0;			return;
+		}
+	else if(dy1 < 1.0e-16) {
+		cx = (pt[0].fx + pt[1].fx)/2.0;			cy = m2 * (cx - mx2) + my2;
+		}
+	else if(dy2 < 1.0e-16) {
+		cx = (pt[2].fx + pt[1].fx)/2.0;			cy = m1 * (cx - mx1) + my1;
+		}
+	else {
+		cx = (m1*mx1-m2*mx2+my2-my1)/(m1-m2);	cy = m1*(cx - mx1) + my1;
+		}
+	dx = pt[1].fx - cx;	dy = pt[1].fy - cy;		r2 = dx * dx + dy * dy;
+}
+
+bool
+Triangle::TestVertex(double x, double y)
+{
+	double dx, dy;
+
+	dx = x-cx;		dx = dx * dx;		dy = y-cy;		dy = dy * dy;
+	return (dx+dy)<r2;
+}
+
+Triangulate::Triangulate(Triangle *t_list)
+{
+	trl = t_list;		edges = 0L;
+}
+
+bool
+Triangulate::AddEdge(fPOINT3D *p1, fPOINT3D *p2)
+{
+	edge *ce, *ne;
+
+	//if edge exists delete both the new and the existing edge
+	for(ce = edges, ne = 0L; (ce); ) {
+		if((ce->p1.fx == p1->fx && ce->p1.fy == p1->fy && ce->p1.fz == p1->fz
+			&& ce->p2.fx == p2->fx && ce->p2.fy == p2->fy && ce->p2.fz == p2->fz)
+			|| (ce->p2.fx == p1->fx && ce->p2.fy == p1->fy && ce->p2.fz == p1->fz
+			&& ce->p1.fx == p2->fx && ce->p1.fy == p2->fy && ce->p1.fz == p2->fz)) {
+			if(ne) ne->next = ce->next;
+			else edges = ce->next;
+			delete ce;					return true;
+			}
+		ne = ce;	ce = ce->next;
+		}
+	//come here for new edge
+	if(ne = new edge()) {
+		ne->p1.fx = p1->fx;		ne->p1.fy = p1->fy;		ne->p1.fz = p1->fz;
+		ne->p2.fx = p2->fx;		ne->p2.fy = p2->fy;		ne->p2.fz = p2->fz;
+		ne->next = edges;		edges = ne;
+		}
+	return false;
+}
+
+bool
+Triangulate::AddVertex(fPOINT3D *v)
+{
+	Triangle *trc, *trn, *tr1;
+	edge *ce, *ae;
+
+	for(trc = trl, trn = 0L, edges = 0L; (trc);) {
+		tr1 = trc->next;
+		//delete triangles whose circumcircle enclose the new vertex
+		if(trc->TestVertex(v->fx, v->fy)) {
+			AddEdge(&trc->pt[0], &trc->pt[1]);		AddEdge(&trc->pt[1], &trc->pt[2]);
+			AddEdge(&trc->pt[0], &trc->pt[2]);
+			if(trn) trn->next = trc->next;
+			else trl = trc->next;
+			if(trl == trc) trl = 0L;	
+			delete trc;
+			}
+		else trn = trc;
+		trc = tr1;
+		}
+	//create new triangles from those edges which where found only once
+	for(ce = edges; (ce); ) {
+		if(trn = new Triangle()) {
+			trn->pt[0].fx = ce->p1.fx;	trn->pt[0].fy = ce->p1.fy;	trn->pt[0].fz = ce->p1.fz;
+			trn->pt[1].fx = ce->p2.fx;	trn->pt[1].fy = ce->p2.fy;	trn->pt[1].fz = ce->p2.fz;
+			trn->pt[2].fx = v->fx;		trn->pt[2].fy = v->fy;		trn->pt[2].fz = v->fz;
+			trn->SetRect();				trn->next = trl;			trl = trn;
+			ae = ce->next;				delete(ce);					ce = ae;
+			}
+		}
+	return true;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Default data vault
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Default::Default()
 {
 	dUnits = cUnits = 0;
-	strcpy(DecPoint, ".");		strcpy(ColSep, ",");
+	rlp_strcpy(DecPoint, 2,  ".");		rlp_strcpy(ColSep, 2, ",");
 	Line_0.width = .4;		Line_1.width = .04,		Line_2.width = 0.016;
 	Line_0.patlength = 6.0;	Line_1.patlength = 0.6;	Line_2.patlength = 0.24;
 	Line_0.color = Line_1.color = Line_2.color = 0x00000000L;	//black
@@ -1932,9 +2263,9 @@ Default::Default()
 	axis_color = 0x0L;	
 	svgAttr = svgScript = currPath = IniFile = 0L;
 	File1 = File2 = File3 = File4 = File5 = File6 = 0L;
-	fmt_date = strdup("Z.V.Y");
-	fmt_time = strdup("H:M:S");
-	fmt_datetime = strdup("Z.V.Y H:M:S");
+	if(fmt_date = (char*)malloc(20)) rlp_strcpy(fmt_date, 20, "Z.V.Y");
+	if(fmt_time = (char*)malloc(20)) rlp_strcpy(fmt_time, 20, "H:M:S");
+	if(fmt_datetime = (char*)malloc(20)) rlp_strcpy(fmt_datetime, 20, "Z.V.Y H:M:S");
 }
 
 Default::~Default()
@@ -2187,16 +2518,16 @@ Default::FileHistory(char *path)
 {
 	char *tmp_path = 0L, *tmp;
 	char **history[] = {&File1, &File2, &File3, &File4, &File5, &File6};
-	int i;
+	int i, j;
 
-	if(path && (tmp_path=(char*)malloc(strlen(path)+10))){
-		strcpy(tmp_path, path);
-		for(i=strlen(path); i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
+	if(path && (tmp_path=(char*)malloc((i=(int)strlen(path))+10))){
+		rlp_strcpy(tmp_path, i+1, path);
+		for(j = i ; i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
 		tmp_path[i] = 0;
 		if(currPath) free(currPath);
-		if(strlen(tmp_path)) currPath = strdup(tmp_path);
+		if(tmp_path[0]) currPath = (char*)memdup(tmp_path, i+1, 0);
 		else currPath = 0L;
-		strcpy(tmp_path, path);
+		rlp_strcpy(tmp_path, j+1, path);
 		if(File1 && strcmp(File1, tmp_path)) {
 			for(i = 0; i < 6 && tmp_path; i++) {
 				if(i && *history[i] && !strcmp(File1, *history[i])){
@@ -2237,9 +2568,7 @@ Default::FileHistory(char *path)
 #define CharCacheSize 1024
 ReadCache::ReadCache()
 {
-	Cache = 0L;
-	idx = max = 0;
-	eof = true;
+	Cache = 0L;		idx = max = 0;		eof = true;
 }
 
 ReadCache::~ReadCache()
@@ -2253,8 +2582,12 @@ ReadCache::Open(char *name)
 {
 	idx = max = 0;
 	eof = true;
-	if(!name) iFile = 0;		//use stdin
+	if(!name) iFile = -1;
+#ifdef USE_WIN_SECURE
+	else if(_sopen_s(&iFile, name, O_BINARY, 0x40, S_IWRITE) || iFile < 0) return false;
+#else
 	else if(-1 ==(iFile = open(name, O_BINARY))) return false;
+#endif
 	Cache = (unsigned char *)malloc((unsigned)(CharCacheSize + 1));
 	if(Cache) return true;
 	return false;
@@ -2263,9 +2596,12 @@ ReadCache::Open(char *name)
 void
 ReadCache::Close()
 {
-	close(iFile);
-	if(Cache) free(Cache);
-	Cache = 0L;
+#ifdef USE_WIN_SECURE
+	if(iFile >= 0) _close(iFile);
+#else
+	if(iFile >= 0) close(iFile);
+#endif
+	if(Cache) free(Cache);				Cache = 0L;
 }
 
 unsigned char
@@ -2275,7 +2611,11 @@ ReadCache::Getc()
 		if(idx < max) return (last = Cache[idx++]);
 		else {
 			do {
+#ifdef USE_WIN_SECURE
+				max = _read(iFile, Cache, CharCacheSize);
+#else
 				max = read(iFile, Cache, CharCacheSize);
+#endif
 				if(max <=0) {
 					eof = true;
 					return 0;
@@ -2299,7 +2639,11 @@ ReadCache::GetField()
 		while(idx < max && Cache[idx] < 43) idx++;
 		if(idx == max){
 			if(max == CharCacheSize) {
+#ifdef USE_WIN_SECURE
+				max = _read(iFile, Cache, CharCacheSize);
+#else
 				max = read(iFile, Cache, CharCacheSize);
+#endif
 				idx = 0;
 				return GetField();
 				}
@@ -2383,8 +2727,8 @@ MemCache::MemCache(unsigned char *ptr)
 :ReadCache()
 {
 	if(ptr) {
-		Cache = (unsigned char*) strdup((char*)ptr);
-		max = strlen((char*)Cache);
+		max = (int)strlen((char*)ptr);
+		Cache = (unsigned char*) memdup(ptr, max+1, 0);
 		eof = false;
 		}
 }
@@ -2464,6 +2808,22 @@ UndoObj::Flush()
 	pcb = &stub1;	cdisp = 0L;	buffers = 0L;
 }
 
+bool
+UndoObj::isEmpty(anyOutput *o)
+{
+	int i;
+
+	if(!buffers) return true;
+	for (i = 0; i < ndisp; i++) if(buffers[i]){
+		if(o && buffers[i]->disp == o ) {
+			if(buffers[i]->count > 0) return false;
+			else return true;
+			}
+		else if(!o && buffers[i]->count > 0) return false;
+		}
+	return true;
+}
+
 //select buffers associated with the current window/widget,
 //create new buffers if called for the first time
 void
@@ -2516,19 +2876,22 @@ UndoObj::KillDisp(anyOutput *o)
 	int i, j, c_buf;
 
 	if(o && buffers) {
-		for(i = c_buf = 0; i < ndisp; i++) {
-			if(buffers[i] && buffers[i]->disp == o)	c_buf = i;	break;
+		for(i = 0, c_buf = -1; i < ndisp; i++) {
+			if(buffers[i] && buffers[i]->disp == o)	{
+				c_buf = i;	break;
+				}
 			}
-		if(!(c_buf)) return;
+		if(c_buf < 0) return;
 		if(buffers[c_buf]->buff) {
 			for(j = 0; j < UNDO_RING_SIZE; j++) {
 				if(buffers[c_buf]->buff[j]) FreeInfo(&buffers[c_buf]->buff[j]);
 				}
 			free(buffers[c_buf]->buff);
 			}
-		free(buffers[i]);	buffers[i] = 0L;
+		free(buffers[c_buf]);	buffers[c_buf] = 0L;
 		}
-	if(o == cdisp) SetDisp(ldisp);
+	if(ldisp && o == cdisp) SetDisp(ldisp);
+	else cdisp = 0L;
 }
 
 //remove references to an invalid (probabbly deleted) object
@@ -2633,6 +2996,16 @@ UndoObj::Restore(bool redraw, anyOutput*o)
 				((EditText*)buff[idx]->loc)->Command(CMD_MRK_DIRTY, cdisp, 0L);
 				}
 			break;
+		case UNDO_TEXTBUF:
+			if(buff[idx]->loc && buff[idx]->data) {
+				target = *((TextBuff*)buff[idx]->data)->pbuff;
+				target = ((TextBuff*)buff[idx]->data)->buff;
+				if(*((TextBuff*)buff[idx]->data)->pbuff) free(*((TextBuff*)buff[idx]->data)->pbuff);
+				*(((TextBuff*)buff[idx]->data)->pbuff) = ((TextBuff*)buff[idx]->data)->buff;
+				*(((TextBuff*)buff[idx]->data)->psize) = ((TextBuff*)buff[idx]->data)->size;
+				*(((TextBuff*)buff[idx]->data)->ppos) = ((TextBuff*)buff[idx]->data)->pos;
+				}
+			break;
 		case UNDO_MUTATE:
 		case UNDO_DEL_GO:
 			((GraphObj*)(buff[idx]->data))->parent = buff[idx]->owner;
@@ -2957,13 +3330,20 @@ UndoObj::ValRect(GraphObj *go, fRECT *rec, DWORD flags)
 	if(0 > NewItem(UNDO_RECT, flags, go, ptr, (void**)rec)) free(ptr);
 }
 
-void
+int
 UndoObj::String(GraphObj *go, char **s, DWORD flags)
 {
 	char *ptr;
+	int iret;
 
-	ptr = (s && *s &&  *(*s)) ? strdup(*(s)):0L;
+	if(s && *s &&  *(*s)){
+		ptr = strdup(*(s));		iret = (int)strlen(*(s));
+		}
+	else {
+		ptr = 0L;				iret = 0;
+		}
 	if(0 > NewItem(UNDO_STRING, flags, go, ptr, (void**)s)) if(ptr) free(ptr);
+	return iret;
 }
 
 void
@@ -3092,6 +3472,23 @@ UndoObj::TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int
 		}
 }
 
+void
+UndoObj::TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o)
+{
+	TextBuff *ptr;
+
+	if(o) SetDisp(o);
+	if(!parent || !psize || !ppos || !pbuff) return;
+	if(ptr = (TextBuff*)calloc(1, sizeof(TextBuff))) {
+		ptr->size = *psize;			ptr->psize = psize;
+		ptr->pos = *ppos;			ptr->ppos = ppos;
+		ptr->pbuff = pbuff;			ptr->buff = (unsigned char*)memdup(*pbuff, ptr->size, 0);
+		if(0 > NewItem(UNDO_TEXTBUF, flags, parent, ptr, (void**)pbuff)) {
+			if(ptr->buff) free(ptr->buff);			free(ptr);
+			}
+		}
+}
+
 int
 UndoObj::NewItem(int cmd, DWORD flags, GraphObj *owner, void *data, void **loc)
 {
@@ -3129,6 +3526,11 @@ UndoObj::FreeInfo(UndoInfo** inf)
 		break;
 	case UNDO_ET:
 		if(((EtBuff*)((*inf)->data))->txt) free(((EtBuff*)((*inf)->data))->txt);
+		free((*inf)->data);
+		break;
+	case UNDO_TEXTBUF:
+		if(((TextBuff*)((*inf)->data))->buff) free(((TextBuff*)((*inf)->data))->buff);
+		free((*inf)->data);
 		break;
 	case UNDO_MUTATE:
 	case UNDO_DEL_GO:
diff --git a/Utils.cpp b/Utils.cpp
index fa95463..0a538db 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -257,7 +257,7 @@ char *str_ltrim(char *str) {
 	}
 
 char *str_rtrim(char *str) {
-	int i;
+	size_t i;
 
 	i = strlen(str);
 	while(i > 0 && str[i-1] <= ' ') str[--i] = '\0';
@@ -268,13 +268,104 @@ char *str_trim(char *str) {
 	str = str_ltrim(str);			return str_rtrim(str);
 }
 
+//remove leading and tailing quotatation
+void rmquot(char *str)
+{
+	size_t i, len;
+	char c;
+
+	if(str && str[0] && (*str == '"' || *str == '\'')) {
+		len = strlen(str);		c = *str;
+		if(str[len-1] == c) {
+			str[len-1] = 0;
+			for(i = 1; i < len; str[i-1] = str[i++]);
+			}
+		}
+}
+
+int strpos(char *needle, char *haystack)
+{
+	int i, j;
+
+	if(!needle || !needle[0] || !haystack || !haystack[0]) return -1;
+	for(i = j = 0; haystack[i]; i++, j=0) {
+		if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
+			if(needle[j] != haystack[i+j]) break; 
+			}
+		if(j && !needle[j]) return i;
+		}
+	return -1;
+}
+
+char *strreplace(char *needle, char *replace, char *haystack)
+{
+	static char *result = 0L;
+	static size_t reslen = 0;
+	size_t i, j, k, l;
+
+	if(!needle || !needle[0] || !haystack || !haystack[0]) haystack;
+	if(!result) result = (char*)malloc(reslen = 100);
+	result[0] = 0;		l = strlen(needle);
+	for(i = j = k = 0; haystack[i]; i++, j=0) {
+		if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
+			if(needle[j] != haystack[i+j]) break; 
+			}
+		if(j && !needle[j]) {
+			if(replace && replace[0]) {
+				if(reslen < (i + (int)strlen(replace) + 10)) {
+					result = (char*)realloc(result, reslen += 100);
+					}
+				for(j = 0; replace[j]; j++) result[k++] = replace[j];
+				}
+			i += (l-1);
+			}
+		else result[k++] = haystack[i];
+		}
+	result[k++] = 0;
+	return result;
+}
+
+char *substr(char *text, int pos1, int pos2)
+{
+	static char *result = 0L;
+	static size_t reslen = 0;
+	int i, j;
+	size_t l;
+
+	if(!text || !text[0]) return 0L;
+	l = strlen(text);
+	if(pos1 < 0) pos1 = 0;			if(pos2 < pos1) pos2 = (int)(l+1);
+	if(!result) result = (char*)malloc(reslen = 100);
+	while (reslen < l) result = (char*) realloc(result, reslen += 100);
+	for(i = 0; i < pos1 && text[i]; i++);
+	for(j = 0; i <= pos2 && text[i]; result[j++] = text[i++]);
+	result[j] = 0;
+	return result;
+}
+
+//copy string in src to dest, returning the stringlength of src
+//   seek better solution for long strings
+int rlp_strcpy(char*dest, int size, char*src)
+{
+	int i;
+
+	if(dest && src) {
+		for(i = 0; i < size; i++) {
+			if(!(dest[i] = src[i])) return i;
+			}
+		dest[i-1] = 0;
+		return i-1;
+		}
+	return 0;
+}
+
 // restyle formula
 void ReshapeFormula(char **text)
 {
 	int i, j, l;
 
 	if(!text || !*text || !**text) return;
-	l = strlen(*text);
+	l = (int)strlen(*text);
 	for(i = j = 0; i < l; i++) {
 		if((*text)[i] == ';') {
 			if((*text)[i+1] == ';' || (*text)[i+1] == '\n') i++;
@@ -282,8 +373,8 @@ void ReshapeFormula(char **text)
 		TmpTxt[j++] = (*text)[i];
 		}
 	TmpTxt[j] = 0;
-	if((int)strlen(TmpTxt) < l && TmpTxt[0]) {
-		free(*text);	*text = strdup(TmpTxt);	
+	if(j && j <= l && TmpTxt[0]) {
+		rlp_strcpy(*text, l+1, TmpTxt);
 		}
 }
 
@@ -294,21 +385,25 @@ void TranslateResult(anyResult *res)
 
 	switch (res->type) {
 	case ET_VALUE:
-		if(res->value == HUGE_VAL) strcpy(tr_text, "inf");
-		else if(res->value == -HUGE_VAL) strcpy(tr_text, "-inf");
+		if(res->value == HUGE_VAL) rlp_strcpy(tr_text, 80, "inf");
+		else if(res->value == -HUGE_VAL) rlp_strcpy(tr_text, 80, "-inf");
+#ifdef USE_WIN_SECURE
+		else sprintf_s(tr_text, 80, "%g", res->value);
+#else
 		else sprintf(tr_text, "%g", res->value);
+#endif
 		res->text = tr_text;				return;
 	case ET_BOOL:
-		sprintf(tr_text, "%s", ((int)res->value) ? "true" : "false"); 
+		rlp_strcpy(tr_text, 80, ((int)res->value) ? (char*)"true" : (char*)"false"); 
 		res->text = tr_text;				return;
 	case ET_DATE:
-		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_date)); 
+		rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_date)); 
 		res->text = tr_text;				return;
 	case ET_TIME:
-		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_time)); 
+		rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_time)); 
 		res->text = tr_text;				return;
 	case ET_DATETIME:
-		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_datetime)); 
+		rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_datetime)); 
 		res->text = tr_text;				return;
 	case ET_TEXT:
 		if(res->text && res->text[0])		return;
@@ -335,7 +430,7 @@ void CleanTags(char *txt, int *i1, int *i2, int *i3)
 					if(no_tags[k][l] != txt[i+l]) break;
 				if(!no_tags[k][l]){
 					na = false;
-					i += ((w=strlen(no_tags[k]))-1);
+					i += ((w=(int)strlen(no_tags[k]))-1);
 					if(i1 && *i1 > i) *i1 -= w;
 					if(i2 && *i2 > i) *i2 -= w;
 					if(i3 && *i3 > i) *i3 -= w;
@@ -374,7 +469,11 @@ char *Nat2Int(char *text)	//format locale number to intranational notation
 
 void WriteNatFloatToBuff(char *buff, double val)
 {
-	WriteFloatToBuff(buff, val);
+#ifdef USE_WIN_SECURE
+	sprintf_s(buff, 20, " %g", val);
+#else
+	sprintf(buff, " %g", val);
+#endif
 	Int2Nat(buff);
 }
 
@@ -385,10 +484,14 @@ bool Txt2Flt(char *txt, double *val)
 	if(txt && txt[0] && val) {
 		if(!txt[1] && (txt[0] == defs.DecPoint[0] || txt[0] < '0' ||
 			txt[0] > '9'))return false;
-		if(txt && txt[0] && (tmp = strdup(txt))){
+		if(txt && txt[0] && (tmp = (char*)memdup(txt, (int)strlen(txt)+1, 0))){
 			Nat2Int(tmp);
 			//the return value of sscanf only roughly identifies a number
+#ifdef USE_WIN_SECURE
+			if(!sscanf_s(tmp,"%lf", val)){
+#else
 			if(!sscanf(tmp,"%lf", val)){
+#endif
 				free(tmp);
 				return false;
 				}
@@ -403,7 +506,7 @@ void RmTrail(char *txt)
 {
 	int i;
 
-	i = strlen(txt);
+	i = (int)strlen(txt);
 	while(i >0 && (txt[i-1] == '0' || txt[i-1] < 32)) txt[--i] = 0;
 	if(i > 1 && txt[i-1] == '.') txt[i-1] = 0;
 }
@@ -420,11 +523,15 @@ double NiceValue(double fv)
 
 char *Int2ColLabel(int nr1, bool uc)
 {
-	static char RetTxt[10];
+	static char RetTxt[12];
 	int i, j, nr = nr1;
 	char base = uc ? 'A' : 'a';
 
+#ifdef USE_WIN_SECURE
+	sprintf_s(RetTxt+8, 4, "%c\0", base + (nr %26));
+#else
 	sprintf(RetTxt+8, "%c\0", base + (nr %26));
+#endif
 	nr /= 26;
 	for (i = 7; nr && i>=0; i--) {
 		j = nr %27;
@@ -446,22 +553,26 @@ char *str2xml(char *str)
 	for(i = j = 0; str[i] && j < 4090; i++) {
 		switch(str[i]) {
 		case '"':
-			j += sprintf(TmpTxt+j, """);
+			j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
 			break;
 		case '&':
-			j += sprintf(TmpTxt+j, "&");
+			j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
 			break;
 		case '<':
-			j += sprintf(TmpTxt+j, "<");
+			j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
 			break;
 		case '>':
-			j += sprintf(TmpTxt+j, ">");
+			j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
 			break;
 		default:
 			if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
 			else {
-				if(mbtowc(&wc, str+i, 1) >0) j += sprintf(TmpTxt+j, 
-					"&#%d;", ((unsigned short)wc));
+				if(mbtowc(&wc, str+i, 1) >0) 
+#ifdef USE_WIN_SECURE
+					j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
+#else
+					j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
+#endif
 				}
 			}
 		}
@@ -471,24 +582,28 @@ char *str2xml(char *str)
 
 // split string str into array of strings using sep as separator
 // return number of lines created in nl
+static char  *split_buf = 0L;
+static int split_buf_size, split_buf_pos;
 char **split(char *str, char sep, int *nl)
 {
-	int i, j, k, l, ns;
-	char **ptr, *txt;
+	int i, j, l, ns;
+	char **ptr;
 
-	if(!str || !sep) return 0L;
-	if(!(txt = strdup(str))) return 0L;
-	k = (int)strlen(txt);
-	for(i = ns = 0; i < k; i++) if(txt[i] == sep) ns++;
-	if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))){
-		free(txt);	return 0L;
-		}
-	for(i = j = l = 0; i < k; i++) {
-		if(txt[i] == sep) {
-			txt[i] = 0;		ptr[l++] = strdup(txt+j);		j = i+1;
+	if(!str || !str[0] || !sep) return 0L;
+	split_buf_pos = 0;
+	add_to_buff(&split_buf, &split_buf_pos, &split_buf_size, str, 0);
+	if(!split_buf || !split_buf_pos) return 0L;
+	for(i = ns = 0; i < split_buf_pos; i++) if(split_buf[i] == sep) ns++;
+	if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))) return 0L;
+	for(i = j = l = 0; i < split_buf_pos; i++) {
+		if(split_buf[i] == sep) {
+			split_buf[i] = 0;
+			ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
+			j = i+1;
 			}
 		}
-	ptr[l++] = strdup(txt+j);	if(nl) *nl = l;		free(txt);
+	ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
+	if(nl) *nl = l;
 	return ptr;
 }
 
@@ -498,13 +613,13 @@ char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
 	char mant[20], expo[20], fmt[10];
 	double num;
 
-	o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
+	o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
 	if(w < (max_width-5)) return num_str;
 	//first try to remove leading zero from exponent
 	for(i = 0; i < slen; i++) if(num_str[i] == 'e') break;
 	if(num_str[i] == 'e') while (num_str[i+2] == '0') {
 		for(j = i+2; num_str[j]; j++) num_str[j] = num_str[j+1];
-		o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
+		o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
 		if(w < (max_width-5)) return num_str;
 		}
 	//no success: reduce the number of digit by rounding
@@ -514,21 +629,91 @@ char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
 		}
 	if(num_str[i] =='e') mant[i] = 0;						k = i - k-1;
 	for(j = 0; num_str[i]; j++, i++) expo[j] = num_str[i];		expo[j] = 0;
+#ifdef USE_WIN_SECURE
+	sscanf_s(mant, "%lf", &num);
+#else
 	sscanf(mant, "%lf", &num);	
+#endif
 	if(k >0) do {
-		sprintf(fmt, "%s.%dlf%s", "%", k, expo);
-		sprintf(num_str, fmt, num);							k--;
-		o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
+#ifdef USE_WIN_SECURE
+		sprintf_s(fmt, 10, "%%.%dlf%s", k, expo);
+		slen = sprintf_s(num_str, 40, fmt, num);		//num_str is much longer than 40
+#else
+		sprintf(fmt, "%%.%dlf%s", k, expo);
+		slen = sprintf(num_str, fmt, num);
+#endif
+		k--;
+		o->oGetTextExtent(num_str, slen, &w, &h);
 		if(w < (max_width-5)) return num_str;
 		}while (k >= 0);
 	//cannot fit: return hash marks instead
-	for(i = w = 0; w < (max_width-5); i++) {
-		sprintf(num_str+i, "#");
-		o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
+	for(i = w = 0; w < (max_width-5) && i < 11; i++) {
+		rlp_strcpy(num_str, i+2, "##########");
+		o->oGetTextExtent(num_str, i+1, &w, &h);
 		}
 	num_str[i-1] = 0;		return num_str;
 }
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// utilities to add a line or number to a text buffer: memory file
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len)
+{
+	if(!len)len = (int)strlen(txt);
+	if(!len) return;
+	if((*pos+len+1)>= *csize) {
+		*csize += 1000;
+		while(*csize < (*pos+len+1)) *csize += 1000;
+		*dest = (char*)realloc(*dest, *csize);
+		}
+	if(*dest) {
+		*pos += rlp_strcpy(*dest+*pos, len+1, txt);
+		}
+}
+
+void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig)
+{
+	int len;
+	char txt[40];
+
+#ifdef USE_WIN_SECURE
+	len = sprintf_s(txt, 40, lsp ? " %d" : "%d", value);
+#else
+	len = sprintf(txt, lsp ? " %d" : "%d", value);
+#endif
+	add_to_buff(dest, pos, csize, txt, len);
+}
+
+void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp)
+{
+	int len;
+	char txt[40];
+
+#ifdef USE_WIN_SECURE
+	len = sprintf_s(txt, 40, lsp ? " %g" : "%g", value);
+#else
+	len = sprintf(txt, lsp ? " %g" : "%g", value);
+#endif
+	add_to_buff(dest, pos, csize, txt, len);
+}
+
+void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp)
+{
+	int len;
+	char txt[40];
+
+	if(value) {
+#ifdef USE_WIN_SECURE
+		len = sprintf_s(txt, 40, lsp ? " 0x%08x" : "0x%08x", value);
+#else
+		len = sprintf(txt, lsp ? " 0x%08x" : "0x%08x", value);
+#endif
+		add_to_buff(dest, pos, csize, txt, len);
+		}
+	else if(lsp) add_to_buff(dest, pos, csize, " 0x0", 4);
+	else add_to_buff(dest, pos, csize, "0x0", 3);
+}
+
 //----------------------------------------------------------------------------
 // bounding rectangle utilities
 //----------------------------------------------------------------------------
@@ -840,19 +1025,17 @@ void InvertPolygon(POINT *pts, int nPts, LineDEF *Line, FillDEF *Fill, RECT *rc,
 void InvertLine(POINT *pts, int nPts, LineDEF *Line, RECT *rc, 
 	anyOutput *o, bool mark)
 {
+	int i;
 	LineDEF OldLine;
-	double minw = defs.GetSize(SIZE_DATA_LINE);
 
 	memcpy(&OldLine, Line, sizeof(LineDEF));
-	if(OldLine.width <= 0.001) memcpy(&OldLine, defs.GetLine(), sizeof(LineDEF));
+	if(OldLine.width <= 0.0001) OldLine.width = 0.0001;
+	for(i = 0; o->un2fiy(OldLine.width) < 1.0 && i < 50; i++) OldLine.width *= 2.0;
 	OldLine.color = mark ? Line->color : 0x00ffffffL;
-	OldLine.width = OldLine.width < minw ? minw * 3.0 : OldLine.width *3.0;
-	o->SetLine(&OldLine);
-	o->oPolyline(pts, nPts);
-	OldLine.width = Line->width;
+	OldLine.width *= 3.0;				o->SetLine(&OldLine);
+	o->oPolyline(pts, nPts);			OldLine.width = Line->width;
 	OldLine.color = mark ? Line->color ^ 0x00ffffffL : Line->color;
-	o->SetLine(&OldLine);
-	o->oPolyline(pts, nPts);
+	o->SetLine(&OldLine);				o->oPolyline(pts, nPts);
 	if(rc) o->UpdateRect(rc, false);
 }
 
@@ -1069,8 +1252,13 @@ void DeleteGO(GraphObj *go)
 	case GO_XYSTAT:			delete((xyStat*)go);		break;
 	case GO_FITFUNC3D:		delete((FitFunc3D*)go);		break;
 	case GO_BEZIER:			delete((Bezier*)go);		break;
+	case GO_TEXTFRAME:		delete((TextFrame*)go);		break;
 	default:
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "Cannot delete Object\nwith Id %ld", go->Id);
+#else
 		sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
+#endif
 		ErrorBox(TmpTxt);
 		//we do not delete the object, probably we recover
 		}
@@ -1116,17 +1304,26 @@ bool BackupFile(char *FileName)
 
 	//no backup necessary if file does not exist
 	if(!(FileExist(FileName))) return true;
-	strcpy(Name, FileName);
-	i = strlen(Name)-1;
+	rlp_strcpy(Name, 512,FileName);
+	i = (int)strlen(Name)-1;
 	if(Name[--i] == '.') Name[i] = 0;
 	else if(Name[--i] == '.') Name[i] = 0;
 	else if(Name[--i] == '.') Name[i] = 0;
 	else return false;
 	i = 1;
 	do {
+#ifdef USE_WIN_SECURE
+		sprintf_s(ext, 6, ".%03d", i);
+		sprintf_s(TmpFileName, 512, "%s%s", Name, ext);
+		if(!(fopen_s(&TheFile, TmpFileName, "r"))) {
+			fclose(TheFile);
+			}
+		else break;
+#else
 		sprintf(ext, ".%03d", i);
 		sprintf(TmpFileName, "%s%s", Name, ext);
 		if((TheFile = fopen(TmpFileName, "r"))) fclose(TheFile);
+#endif
 		i++;
 	} while (i < 999 && TheFile);
 	if(i >= 999) {								//too many backups exist already
@@ -1146,7 +1343,11 @@ bool IsRlpFile(char *FileName)
 	char Line[10];
 	bool bRet = false;
 
+#ifdef USE_WIN_SECURE
+	if(fopen_s(&TheFile, FileName, "r")) return false;
+#else
 	if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+#endif
 	fread(Line, 1, 8, TheFile);
 	Line[5] = 0;
 	if(0 == strcmp(Line, ";RLP "))bRet = true;
@@ -1160,7 +1361,11 @@ bool IsXmlFile(char *FileName)
 	char Line[10];
 	bool bRet = false;
 
+#ifdef USE_WIN_SECURE
+	if(fopen_s(&TheFile, FileName, "r")) return false;
+#else
 	if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+#endif
 	fread(Line, 1, 8, TheFile);
 	Line[6] = 0;
 	if(0 == strcmp(Line, "<?xml "))bRet = true;
@@ -1172,11 +1377,14 @@ bool FileExist(char *FileName)
 {
 	FILE *TheFile;
 
-
+#ifdef USE_WIN_SECURE
+	if(ENOENT == fopen_s(&TheFile, FileName, "r")) return false;
+#else
 	if(0L ==(TheFile = fopen(FileName, "r"))) {
 		if(errno == ENOENT) return false;
 		return true;
 		}
+#endif
 	fclose(TheFile);
 	return true;
 }
diff --git a/Version.h b/Version.h
index d899ea7..95a98b5 100755
--- a/Version.h
+++ b/Version.h
@@ -16,4 +16,4 @@
 //    along with RLPlot; if not, write to the Free Software
 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 //
-#define SZ_VERSION  "1.1.2"
+#define SZ_VERSION  "1.2"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index 0eac824..e59c53b 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -56,12 +56,14 @@ PrintWin *Printer = 0L;
 char *SaveDataAsName(char *oldname)
 {
 	static char szFile[500], szFileTitle[256];
-	static char szFilter[] = "RLPlot workbook (*.rlw)\0*.rlw\0data files (*.csv)\0*.csv\0tab separated (*tsv)\0"
+	static char szFilter[] = "RLPlot workbook (*.rlw)\0*.rlw\0data files (*.csv)\0*.csv\0tab separated (*.tsv)\0"
 		"*.tsv\0XML (*.xml)\0*.xml\0";
 	OPENFILENAME ofn;
+	int i, j, cb;
+	char *ext;
 
 	szFile[0] = '\0';
-	if(oldname)strcpy(szFile, oldname);
+	if(oldname)rlp_strcpy(szFile, 500, oldname);
 	memset(&ofn, 0, sizeof(OPENFILENAME));
 	ofn.lStructSize = sizeof(OPENFILENAME);
 	ofn.hwndOwner = GetFocus();
@@ -76,10 +78,19 @@ char *SaveDataAsName(char *oldname)
 	ofn.lpstrTitle = "Save Data As";
 
 	if(GetSaveFileName(&ofn)){
+		if(!(cb = (int)strlen(szFile)) || !szFile[0])return 0L;
+		if(cb < 4 || szFile[cb-4] != '.'){
+			for(i = j = 0; (j>>1) < (int)(ofn.nFilterIndex-1); i++) {
+				if(szFilter[i] == '\0') j++;
+				}
+			ext = szFilter+i;
+			for(i = 0; ext[i] && ext[i] != '*'; i++);
+			rlp_strcpy(szFile+cb, 5, ext+i+1);
+			}
 		defs.FileHistory(szFile);
 		return szFile;
 		}
-	else return NULL;
+	else return 0L;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -91,7 +102,7 @@ char *SaveGraphAsName(char *oldname)
 	OPENFILENAME ofn;
 
 	szFile[0] = '\0';
-	if(oldname)strcpy(szFile, oldname);
+	if(oldname)rlp_strcpy(szFile, 500, oldname);
 	memset(&ofn, 0, sizeof(OPENFILENAME));
 	ofn.lStructSize = sizeof(OPENFILENAME);
 	ofn.hwndOwner = GetFocus();
@@ -121,7 +132,7 @@ char *OpenGraphName(char *oldname)
 	OPENFILENAME ofn;
 
 	szFile[0] = '\0';
-	if(oldname)strcpy(szFile, oldname);
+	if(oldname)rlp_strcpy(szFile, 500, oldname);
 	memset(&ofn, 0, sizeof(OPENFILENAME));
 	ofn.lStructSize = sizeof(OPENFILENAME);
 	ofn.hwndOwner = GetFocus();
@@ -153,7 +164,7 @@ char *OpenDataName(char *oldname)
 	OPENFILENAME ofn;
 
 	szFile[0] = '\0';
-	if(oldname)strcpy(szFile, oldname);
+	if(oldname)rlp_strcpy(szFile, 500, oldname);
 	memset(&ofn, 0, sizeof(OPENFILENAME));
 	ofn.lStructSize = sizeof(OPENFILENAME);
 	ofn.hwndOwner = GetFocus();
@@ -188,7 +199,7 @@ void OpenExportName(GraphObj *g, char *oldname)
 
 	szFile[0] = '\0';
 	if(!g) return;
-	if(oldname)strcpy(szFile, oldname);
+	if(oldname)rlp_strcpy(szFile, 500, oldname);
 	memset(&ofn, 0, sizeof(OPENFILENAME));
 	ofn.lStructSize = sizeof(OPENFILENAME);
 	ofn.hwndOwner = GetFocus();
@@ -203,21 +214,21 @@ void OpenExportName(GraphObj *g, char *oldname)
 	ofn.lpstrTitle = "Export Graph";
 
 	if(g && GetSaveFileName(&ofn)){
-		i = strlen(szFile);
+		i = (int)strlen(szFile);
 		g->Command(CMD_BUSY, 0L, 0L);
-		if(0==stricmp(".svg", szFile+i-4)) {
+		if(0==_stricmp(".svg", szFile+i-4)) {
 			DoExportSvg(g, szFile, 0L);
 			}
-		else if(0==stricmp(".wmf", szFile+i-4)) {
+		else if(0==_stricmp(".wmf", szFile+i-4)) {
 			DoExportWmf(g, szFile, 600.0f, 0L);
 			}
-		else if(0==stricmp(".eps", szFile+i-4)) {
+		else if(0==_stricmp(".eps", szFile+i-4)) {
 			DoExportEps(g, szFile, 0L);
 			}
-		else if(0==stricmp(".tif", szFile+i-4)) {
+		else if(0==_stricmp(".tif", szFile+i-4)) {
 			DoExportTif(g, szFile, 0L);
 			}
-		else if(0==stricmp(".tiff", szFile+i-5)) {
+		else if(0==_stricmp(".tiff", szFile+i-5)) {
 			DoExportTif(g, szFile, 0L);
 			}
 		else ErrorBox("Unknown file extension or format");
@@ -332,7 +343,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
 LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
 LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
 
-long FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
+LRESULT FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 {
 	static POINT line[5];
 	static int cp_mark = 0;
@@ -432,13 +443,13 @@ void TestClipboard(GraphObj *g)
 		else if((hmem = GetClipboardData(cf_rlpgraph)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
-	else if(g->Id == GO_PAGE) {
+	else if(g->Id == GO_PAGE || g->Id == GO_GRAPH) {
 		if((hmem = GetClipboardData(cf_rlpobj)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		else if((hmem = GetClipboardData(cf_rlpgraph)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
-	else if(g->Id == GO_GRAPH) TestClipboard(g->parent);
+	else TestClipboard(g->parent);
 	if(hmem) GlobalUnlock(hmem);
 	CloseClipboard();
 }
@@ -457,7 +468,7 @@ void CopyText(char *txt, int len)
 	unsigned char* buf;
 
 	if(!txt || !txt[0]) return;
-	if(!len) len = strlen(txt);
+	if(!len) len = (int)strlen(txt);
 	OpenClipboard(MainWnd);
 	EmptyClipboard();
 	if(hmem = GlobalAlloc(GMEM_MOVEABLE, len+2)) {
@@ -477,7 +488,7 @@ unsigned char* PasteText()
 	
 	OpenClipboard(MainWnd);
 	if((hmem = GetClipboardData(CF_TEXT)) && (ptr = (unsigned char*) GlobalLock(hmem))){
-		ret = (unsigned char*) strdup((char*)ptr);
+		ret = (unsigned char*) _strdup((char*)ptr);
 		}
 	if(hmem) GlobalUnlock(hmem);
 	CloseClipboard();
@@ -497,13 +508,51 @@ void GetDesktopSize(int *width, int *height)
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get long reference to pointer (win64-compatibility)
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void **ptrs = 0L;
+static size_t s_ptrs = 0;
+static size_t n_ptrs = 1;
+
+long lptrref(void* ptr)
+{
+	size_t i;
+
+	if((n_ptrs +1) > s_ptrs){
+		ptrs = (void **)realloc(ptrs, (s_ptrs += 1000) * sizeof(void*));
+		}
+	if(!ptrs) return 0L;
+	for(i = 1; i < n_ptrs; i++){
+		if(ptrs[i]== ptr) return (long)i;
+		if(ptr && !ptrs[i]){
+			ptrs[i] = ptr;
+			return (long)i;
+			}
+		}
+	//new pointer
+	ptrs[n_ptrs++] = ptr;
+	return (long)(n_ptrs-1);
+}
+
+void *reflptr(long ref)
+{
+	if(ref > 0 && ref < (long)n_ptrs && ptrs) return ptrs[ref];
+	return 0L;
+}
+
+void noreflptr(long ref)
+{
+	if(ref > 0 && ref < (long)n_ptrs && ptrs) ptrs[ref]=0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Common code for any Windows output class
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool com_oTextOut(int x, int y, char *txt, int cb, 
 	HFONT *hFont, HDC *dc, TextDEF *td, bool win95mode, anyOutput *o)
 {
 	XFORM xf;
-	w_char *uc;
+	WCHAR *uc;
 	int i, ix, iy, align;
 
 	if(!*hFont || !txt || !txt[0]) return false;
@@ -534,19 +583,19 @@ bool com_oTextOut(int x, int y, char *txt, int cb,
 		xf.eDx = (float)x;
 		xf.eDy = (float)y;
 		SetWorldTransform(*dc, &xf);
-		if(td->Font==FONT_GREEK && (uc=(w_char*)calloc(strlen(txt)+1, sizeof(w_char)))) {
+		if(td->Font==FONT_GREEK && (uc=(WCHAR *)calloc(strlen(txt)+1, sizeof(WCHAR)))) {
 			for(i = 0; txt[i]; i++) {
 				if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
 				else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
 				else uc[i] = txt[i];
 				}
 			TextOutW(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), uc, 
-				(cb > 0) ? cb : strlen(txt));
+				(cb > 0) ? cb : (int)strlen(txt));
 			free(uc);
 			}
 		else {
 			TextOut(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), txt, 
-				(cb > 0) ? cb : strlen(txt));
+				(cb > 0) ? cb : (int)strlen(txt));
 			}
 //		DrawText(*dc, txt, (cb> 0)? cb : strlen(txt), 0L /*LPRECT*/, uFormat);
 		ModifyWorldTransform(*dc, &xf, MWT_IDENTITY);
@@ -554,19 +603,19 @@ bool com_oTextOut(int x, int y, char *txt, int cb,
 		return true;
 		}
 	else {
-		if(!win95mode && td->Font==FONT_GREEK && (uc=(w_char*)calloc(strlen(txt)+1, sizeof(w_char)))) {
+		if(!win95mode && td->Font==FONT_GREEK && (uc=(WCHAR *)calloc(strlen(txt)+1, sizeof(WCHAR)))) {
 			for(i = 0; txt[i]; i++) {
 				if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
 				else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
 				else uc[i] = txt[i];
 				}
 			TextOutW(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), uc, 
-				(cb > 0) ? cb : strlen(txt));
+				(cb > 0) ? cb : (int)strlen(txt));
 			free(uc);
 			return true;
 			}
 		else if(TextOut(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), txt, 
-			(cb > 0) ? cb : strlen(txt))) return true;
+			(cb > 0) ? cb : (int)strlen(txt))) return true;
 		}
 	return false;
 }
@@ -590,7 +639,7 @@ bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet,
 		if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB))
 			FontRec.lfHeight = o->un2iy(set->fSize*0.71);
 		else FontRec.lfHeight = TxtSet->iSize;
-		if(FontRec.lfHeight <8) FontRec.lfHeight = 8;
+		if(FontRec.lfHeight <2) FontRec.lfHeight = 2;
 		FontRec.lfWidth = 0;
 		if(win95mode) {				//Win 95, 98
 			FontRec.lfEscapement = iround(TxtSet->RotBL*10);		//text angle
@@ -612,17 +661,17 @@ bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet,
 		default:
 			FontRec.lfCharSet = ANSI_CHARSET;
 			FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
-			strcpy(FontRec.lfFaceName, "Arial");
+			rlp_strcpy(FontRec.lfFaceName, 32, "Arial");
 			break;
 		case FONT_GREEK:		case FONT_TIMES:
 			FontRec.lfCharSet = ANSI_CHARSET;
 			FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
-			strcpy(FontRec.lfFaceName, "Times New Roman");
+			rlp_strcpy(FontRec.lfFaceName, 32, "Times New Roman");
 			break;
 		case FONT_COURIER:
 			FontRec.lfCharSet = ANSI_CHARSET;
 			FontRec.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
-			strcpy(FontRec.lfFaceName, "Courier New");
+			rlp_strcpy(FontRec.lfFaceName, 32, "Courier New");
 			break;
 			}
 		newFont = CreateFontIndirect(&FontRec);
@@ -859,7 +908,7 @@ BitMapWin::oGetTextExtent(char *text, int cb, int *width, int *height)
 	double si, csi, d;
 
 	if(!text) return false;
-	if(!GetTextExtentPoint32(memDC, text, cb ? cb : strlen(text), &TextExtent))return false;
+	if(!GetTextExtentPoint32(memDC, text, cb ? cb : (int)strlen(text), &TextExtent))return false;
 	if(fabs(TxtSet.RotBL) >0.01) {
 		si = fabs(sin(TxtSet.RotBL * 0.01745329252));	csi = fabs(cos(TxtSet.RotBL * 0.01745329252));
 		d = si > csi ? 1.0/si : 1.0/csi;
@@ -1341,7 +1390,7 @@ OutputWin::FileHistory()
 	if(!(hSubMenu = GetSubMenu(GetMenu(hWnd), 0))) return;
 	if(!HistMenuSize) AppendMenu(hSubMenu, MF_SEPARATOR, 0L, 0L);
     for(i = 0; i < 6 && *history[i]; i++) {
-		k = strlen(*history[i]);
+		k = (int)strlen(*history[i]);
 		for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++);
 		if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++;
 		if(i < HistMenuSize) {
@@ -1363,8 +1412,13 @@ OutputWin::CreateNewWindow(void *g)
 		WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
 		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
 		CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
-	SetWindowLong(hWnd, 0, (long)g);		// g is the parent graphic obj
-	SetWindowLong(hWnd, GWL_USERDATA, (long)this);
+#if _MSC_VER >= 1400
+	SetWindowLongPtr(hWnd, 0, lptrref(g));		// g is the parent graphic obj
+	SetWindowLongPtr(hWnd, GWL_USERDATA, lptrref(this));
+#else
+	SetWindowLong(hWnd, 0, lptrref(g));			// g is the parent graphic obj
+	SetWindowLong(hWnd, GWL_USERDATA, lptrref(this));
+#endif
 	if(BitMapWin::Erase(0x00cbcbcb)) {
 		GetClientRect(hWnd, &ClientRect);
 		InvalidateRect(hWnd, &ClientRect, FALSE);
@@ -1582,19 +1636,19 @@ PrintWin::PrintWin()
 	while(TmpTxt[i] && TmpTxt[i] != ',') i++;
 	TmpTxt[i] = 0;
 	if (i >2) {
-		PrintDevice = strdup(TmpTxt);
+		PrintDevice = _strdup(TmpTxt);
 		i++;
 		j = i;
 		while(TmpTxt[i] && TmpTxt[i] != ',') i++;
 		if(i-j > 2) {
 			TmpTxt[i] = 0;
-			PrintDriver = strdup(TmpTxt+j);
+			PrintDriver = _strdup(TmpTxt+j);
 			i++;
 			j = i;
 			while(TmpTxt[i] && TmpTxt[i] != ',') i++;
 			if(i-j > 2) {
 				TmpTxt[i] = 0;
-				PrintPort = strdup(TmpTxt+j);
+				PrintPort = _strdup(TmpTxt+j);
 				//Get default paper setup
 				if(hDC = CreateDC(PrintDriver, PrintDevice, PrintPort, 0L)) { 
 					pw = GetDeviceCaps(hDC, PHYSICALWIDTH);
@@ -1815,14 +1869,14 @@ void FindBrowser()
 					}
 				else text[i+1] = 0;
 				}
-			WWWbrowser = strdup(text+1);
+			WWWbrowser = _strdup(text+1);
 			}
 		else {
 			for(i = size-1; i >5; i--) {
-				if(0 == stricmp(text+i-3, ".exe")) break;
+				if(0 == _stricmp(text+i-3, ".exe")) break;
 				else text[i] = 0;
 				}
-			WWWbrowser = strdup(text);
+			WWWbrowser = _strdup(text);
 			}
 		}
 	//find user default data directory
@@ -1833,7 +1887,7 @@ void FindBrowser()
 		size= 599;
 		RegQueryValueEx(hdl, "HOMEPATH", 0, 0, (unsigned char*)(text+strlen(text)), 
 			(unsigned long*)&size);
-		defs.currPath = strdup(text);
+		defs.currPath = _strdup(text);
 		}
 	//find user application data directory
 	if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, 
@@ -1841,8 +1895,12 @@ void FindBrowser()
 		KEY_READ, &hdl)) {
 		text[0] = 0;	size=599;
 		RegQueryValueEx(hdl, "AppData", 0, 0, (unsigned char*)text, (unsigned long*)&size);
+#ifdef USE_WIN_SECURE
+		strcat_s(text, 600, "\\RLPlot");
+#else
 		strcat(text, "\\RLPlot");
-		defs.IniFile = strdup(text);
+#endif
+		defs.IniFile = _strdup(text);
 		}
 	//find country specific information
 	//  its not a perfect place to do it, but a good one
@@ -1861,7 +1919,7 @@ void FindBrowser()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Windos entry point
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
+int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
 	 LPSTR lpCmdLine, int nCmdShow )
 {
 	WNDCLASS wndclass;
@@ -1871,14 +1929,15 @@ WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
 	//OS dependent initialization
 	dlgtxtheight = 16;
 
-	if(lpCmdLine && lpCmdLine[0] && FileExist(lpCmdLine)) LoadFile = strdup(lpCmdLine);
-	else if(lpCmdLine) {								//probably Unicode 
+	if(lpCmdLine && lpCmdLine[0] && FileExist(lpCmdLine)) LoadFile = _strdup(lpCmdLine);
+	else if(lpCmdLine) {								//probably Unicode
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s", lpCmdLine);
+#else
 		sprintf(TmpTxt, "%s", lpCmdLine);
-		if(TmpTxt[0] == '"'){
-			strcpy(TmpTxt, TmpTxt+1);
-			if(TmpTxt[0]) TmpTxt[strlen(TmpTxt)-1] = 0;
-			}
-		if(TmpTxt[0]) LoadFile= strdup(TmpTxt);
+#endif
+		rmquot(TmpTxt);
+		if(TmpTxt[0]) LoadFile= _strdup(TmpTxt);
 		}
 	hInstance = hInst;
 	wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS;
@@ -1913,7 +1972,7 @@ WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
 	if(Printer) delete Printer;
 	InitTextCursor(false);
 	UnregisterClass(name, hInstance);
-	return msg.wParam;
+	return (int)msg.wParam;
 }
 
 void CopyData(GraphObj *g, unsigned int cf)
@@ -1935,7 +1994,7 @@ void CopyData(GraphObj *g, unsigned int cf)
 		if(cf == cf_rlpxml && g->Command(CMD_COPY_XML, &dt, 0L)) break;
 		else return;
 		}
-	cb = strlen((char*)dt);
+	cb = (long)strlen((char*)dt);
 	if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+2)) {
 		if(buf = (unsigned char *)GlobalLock(hmem)) {
 			memcpy(buf, dt, cb+1);
@@ -2039,8 +2098,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 	HDC dc;
 	int cc;
 
-	g = (GraphObj *) GetWindowLong(hwnd, 0);
-	w = (OutputWin *) GetWindowLong(hwnd, GWL_USERDATA);
+	g = (GraphObj *) reflptr(GetWindowLong(hwnd, 0));
+	w = (OutputWin *) reflptr(GetWindowLong(hwnd, GWL_USERDATA));
 	if(g && w) switch(message) {
 	case WM_SETFOCUS:
 		if(g->Id == GO_GRAPH) CurrGraph = (Graph*)g;
@@ -2152,18 +2211,31 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			return 0;
 		case CM_PASTE:
 			w->MouseCursor(MC_WAIT, true);
-			if(g->Id == GO_SPREADDATA || g->Id == GO_PAGE ||
-				g->Id == GO_GRAPH) TestClipboard(g);
+			if(g->Id == GO_SPREADDATA) TestClipboard(g);
+			else if(g->Id == GO_PAGE || g->Id == GO_GRAPH){
+				if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(CMD_PASTE, 0L, w));
+				else TestClipboard(g);
+				}
 			g->Command(CMD_MOUSECURSOR, 0L, w);
 			return 0;
 		case CM_COPY:			case CM_CUT:
 			EmptyClip();
+			if(g->Id != GO_SPREADDATA && CurrGO && CurrGO->Id == GO_TEXTFRAME) {
+				if(CurrGO->Command(CMD_COPY, 0L, w))return 0;
+				}
 			OpenClipboard(hwnd);
 			if(g->Id == GO_SPREADDATA && g->Command(wParam == CM_CUT ? CMD_CUT : CMD_QUERY_COPY, 0L, w)) {
 				SetClipboardData(CF_TEXT, NULL);
 				SetClipboardData(CF_SYLK, NULL);
 				SetClipboardData(cf_rlpxml, NULL);
 				}
+			else if(g->Id == GO_PAGE) {
+				SetClipboardData(CF_METAFILEPICT, NULL);
+				SetClipboardData(CF_BITMAP, NULL);
+				SetClipboardData(cf_rlpgraph, NULL);
+				if(g->Id == GO_PAGE && CurrGraph) CopyGraph(CurrGraph, cf_rlpobj);
+				copy_obj = g;
+				}
 			CloseClipboard();
 			return 0;
 		case CM_UPDATE:
@@ -2171,6 +2243,9 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			return 0;
 		case CM_COPYGRAPH:
 			EmptyClip();
+			if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
+				if(CurrGO->Command(CMD_COPY, 0L, w))return 0;
+				}
 			OpenClipboard(GetFocus());
 			SetClipboardData(CF_METAFILEPICT, NULL);
 			SetClipboardData(CF_BITMAP, NULL);
@@ -2358,15 +2433,26 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_DELCOL:
 			g->Command(CMD_DELCOL, 0L, w);
 			return 0;
+		case CM_REPCMEANS:
+			if(g->data) rep_compmeans(g, g->data);
+			return 0;
 		case CM_REPANOV:
 			if(g->data) rep_anova(g, g->data);
 			return 0;
 		case CM_REPREGR:
 			if(g->data) rep_regression(g, g->data);
 			return 0;
+		case CM_REPTWOWAY:
+			if(g->data) rep_twowaytable(g, g->data);
+			return 0;
 		default:
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "Command 0x%x (%d)\nreceived", wParam & 0xffff,
+				wParam & 0xffff);
+#else
 			sprintf(TmpTxt, "Command 0x%x (%d)\nreceived", wParam & 0xffff,
 				wParam & 0xffff);
+#endif
 			MessageBox(hwnd, TmpTxt, "Info", MB_OK | MB_ICONINFORMATION);
 		}
 		return 0;
@@ -2388,7 +2474,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		EndPaint(hwnd, &ps);
 		break;
 	}
-	return DefWindowProc(hwnd, message, wParam, lParam);
+	return (long)DefWindowProc(hwnd, message, wParam, lParam);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2396,7 +2482,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 const char dlgname[] = "RLDLGWIN";
 
-long FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
+LRESULT FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 {
 	OutputWin *w;
 	tag_DlgObj *d;
@@ -2405,8 +2491,8 @@ long FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 	MouseEvent mev;
 	int i, cc;
 
-	d = (tag_DlgObj *) GetWindowLong(hwnd, 0);
-	w = (OutputWin *) GetWindowLong(hwnd, GWL_USERDATA);
+	d = (tag_DlgObj *) reflptr(GetWindowLong(hwnd, 0));
+	w = (OutputWin *) reflptr(GetWindowLong(hwnd, GWL_USERDATA));
 	switch(message) {
 	case WM_CREATE:
 		break;
@@ -2422,9 +2508,12 @@ long FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			d->Command(CMD_UNLOCK, 0L, w);
 			d->Command(CMD_ENDDIALOG, 0L, w);
 			SetWindowLong(hwnd, 0, NULL);
+			noreflptr(GetWindowLong(hwnd, 0));
 			}
 		if(w) {
+			w->hWnd = 0L;
 			SetWindowLong(hwnd, GWL_USERDATA, NULL);
+			noreflptr(GetWindowLong(hwnd, GWL_USERDATA));
 			delete w;
 			}
 		break;
@@ -2512,8 +2601,8 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 	w = new OutputWin(0L, hDlg);
 	w->units = defs.cUnits;
 	if(hDlg && w && w->Erase(0x00e0e0e0L)) {
-		SetWindowLong(hDlg, GWL_USERDATA, (long)w);
-		SetWindowLong(hDlg, 0, (long)d);
+		SetWindowLong(hDlg, GWL_USERDATA, lptrref(w));
+		SetWindowLong(hDlg, 0, lptrref(d));
 		if(flags & 0x01) {					//center on screen
 			GetWindowRect(hDlg, &BoxRec);
 			GetClientRect(GetDesktopWindow(), &DeskRect);
@@ -2553,6 +2642,15 @@ void ShowDlgWnd(void *hDlg)
 	SetFocus((HWND)hDlg);
 }
 
+void ResizeDlgWnd(void *hDlg, int w, int h)
+{
+	HWND hwnd = (HWND)hDlg;
+	RECT rc;
+
+	GetWindowRect(hwnd, &rc);
+	SetWindowPos(hwnd, HWND_TOPMOST, rc.left, rc.top, w, h, 0);
+	ShowDlgWnd(hDlg);
+}
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // OS independent interface to Windows specific classes
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/exprlp.cpp b/exprlp.cpp
index 309dbdc..4b0a5e5 100755
--- a/exprlp.cpp
+++ b/exprlp.cpp
@@ -1,35 +1,35 @@
-//exprlp.cpp, Copyright (c) 2002-2006 R.Lackner
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <locale.h>
-#include <unistd.h>			//required for unlink()
-#include "Version.h"
-#include "rlplot.h"
-
-int file_fmt = FF_UNKNOWN;
-bool bQuiet = false, bSVGtype = false, bDelete = false;
-char *szFile1 = 0L, *szFile2 = 0L;
-int dlgtxtheight = 12;				//stub: not used
+//exprlp.cpp, Copyright (c) 2002-2006 R.Lackner
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>			//required for unlink()
+#include "Version.h"
+#include "rlplot.h"
+
+int file_fmt = FF_UNKNOWN;
+bool bQuiet = false, bSVGtype = false, bDelete = false;
+char *szFile1 = 0L, *szFile2 = 0L;
+int dlgtxtheight = 12;				//stub: not used
 char *name1, *name2;				//the filenames
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// direct messages to console
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void InfoBox(char *Msg)
-{
-	if(!bQuiet) fprintf(stderr, "exprlp INFO: %s\n", Msg);
-}
-
-void ErrorBox(char *Msg)
-{
-	if(!bQuiet) fprintf(stderr, "exprlp ERROR: %s\n", Msg);
-}
-
-bool YesNoBox(char *Msg)
-{
-return false;
-}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// direct messages to console
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void InfoBox(char *Msg)
+{
+	if(!bQuiet) fprintf(stderr, "exprlp INFO: %s\n", Msg);
+}
+
+void ErrorBox(char *Msg)
+{
+	if(!bQuiet) fprintf(stderr, "exprlp ERROR: %s\n", Msg);
+}
+
+bool YesNoBox(char *Msg)
+{
+return false;
+}
 
 int YesNoCancelBox(char *Msg)
 {
@@ -52,184 +52,184 @@ unsigned char* PasteText()
 {
 	return 0L;
 }
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a root object to handle I/O
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class ExpRoot:public GraphObj{
-public:
-	ExpRoot(char *file1, char *file2);
-	~ExpRoot();
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-
-private:
-	GraphObj *go;
-};
-
-ExpRoot::ExpRoot(char *file1, char *file2):GraphObj(0L, 0L)
-{
-	if(file1 && strcmp("-", file1)) name1 = file1;
-	else name1 = 0L;
-	if(file2 && strcmp("-", file2)) name2 = file2;
-	else name2 = 0L;
-	go = 0L;
-	OpenGraph(this, name1, 0L, false);
-	if(bDelete && name1 && name1[0]) unlink(name1);
-}
-
-ExpRoot::~ExpRoot()
-{
-	if(go) {
-		DeleteGO(go);
-		if(!bQuiet)fprintf(stderr, "Object deleted after read\n");
-		}
-}
-
-bool
-ExpRoot::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i;
-
-	switch(cmd) {
-	case CMD_DROP_GRAPH:
-		go = (GraphObj*)tmpl;
-		if(go) {
-			go->Command(CMD_SET_DATAOBJ, 0L, 0L);
-			switch(file_fmt){
-			case FF_SVG:
-				DoExportSvg(go, name2, bSVGtype ? 1L : 0L);
-				break;
-			case FF_WMF:
-				DoExportWmf(go, name2, 600.0f, 0L);
-				break;
-			case FF_EPS:
-				DoExportEps(go, name2, 0L);
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a root object to handle I/O
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ExpRoot:public GraphObj{
+public:
+	ExpRoot(char *file1, char *file2);
+	~ExpRoot();
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+
+private:
+	GraphObj *go;
+};
+
+ExpRoot::ExpRoot(char *file1, char *file2):GraphObj(0L, 0L)
+{
+	if(file1 && strcmp("-", file1)) name1 = file1;
+	else name1 = 0L;
+	if(file2 && strcmp("-", file2)) name2 = file2;
+	else name2 = 0L;
+	go = 0L;
+	OpenGraph(this, name1, 0L, false);
+	if(bDelete && name1 && name1[0]) unlink(name1);
+}
+
+ExpRoot::~ExpRoot()
+{
+	if(go) {
+		DeleteGO(go);
+		if(!bQuiet)fprintf(stderr, "Object deleted after read\n");
+		}
+}
+
+bool
+ExpRoot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i;
+
+	switch(cmd) {
+	case CMD_DROP_GRAPH:
+		go = (GraphObj*)tmpl;
+		if(go) {
+			go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+			switch(file_fmt){
+			case FF_SVG:
+				DoExportSvg(go, name2, bSVGtype ? 1L : 0L);
+				break;
+			case FF_WMF:
+				DoExportWmf(go, name2, 600.0f, 0L);
+				break;
+			case FF_EPS:
+				DoExportEps(go, name2, 0L);
 				break;
 			case FF_RLP:
 				SaveGraphAs(go);
-				break;
-			default:
-				ErrorBox("Unknown file extension or format of destination");
-				}
-			DeleteGO(go);
-			go = 0L;
-			}
-		break;
-		}
-	return true;
-}
-
-
-int Usage()
-{
-	printf("______________________________________________________________\n");
-	printf("\nexprlp: RLPlot export utility, version %s.\n", SZ_VERSION);
-	printf("Copyright (C) 2002-2005 R. Lackner\n");
-	printf("This is free software published under the GNU\n");
-	printf("general public licence (GPL).\n");
-	printf("\nUsage: exprlp [options] <input> [options] [<output>]\n");
-	printf("\nOptions:\n");
-	printf("   -      use stdin/stdout as input or output file; requires\n");
-	printf("             that file format is set by -e | -s | -w option\n");
-	printf("             not an option in the strict sense\n");
-	printf("   -h     print this information\n");
-	printf("   -d     delete input file after read\n");
-	printf("   -e     output Encapsulated PostScript, *.eps\n");
-	printf("   -s     output Scalable Vector Graphics, *.svg\n");
-	printf("   -S     like -s, start output with \"Content-Type: image/svg+xml\"\n");
-	printf("   -v     print RLPlot version\n");
-	printf("   -w     output Windows Meta File, *.wmf\n");
-	printf("   -q     quiet mode: suppress output to the console\n");
-	printf("\nExamples:\n");
-	printf("   exprlp foo.rlp foo.svg      ;exports Scalable Vector Graphics\n");
-	printf("   exprlp -q foo.rlp foo.eps   ;exports Encapsulated PostScript, no messages\n");
-	printf("   exprlp foo.rlp foo.wmf      ;exports Windows Meta File\n");
-	printf("   exprlp -sq foo.rlp -        ;exports SVG to the console, no messages\n");
-	printf("   exprlp -eq - -              ;converts inputfile from stdin to EPS\n");
-	printf("                                   on stdout: useful for pipes\n");
-	printf("\n switch character is either \'-\' or \'/\'\n");
-	printf("______________________________________________________________\n\n");
-	if(szFile1) free(szFile1);	if(szFile2) free(szFile2);
-	szFile1 = szFile2 = 0L;
-	return 1;
-}
-
-int main (int argc, char **argv)
-{
-	ExpRoot *base = 0L;
-	int i, j, k;
-
-	for (i = 1, j = 0; i < argc; i++) {
-		if(argv[i][0] == '-' || (argv[i][0] == '/' && strlen(argv[i]) < 5)) {
-			//check for switch
-			for(k = 1; argv[i][k-1]; k++) {
-				switch(argv[i][k]){
-				case 'h':	case 'H':	case '?':
-					return Usage();
-				case 'd':
-					bDelete = true;
-					break;
-				case 'S':
-					bSVGtype = true;
-				case 's':
-					file_fmt = FF_SVG;
-					break;
-				case 'e':	case 'E':
-					file_fmt = FF_EPS;
-					break;
+				break;
+			default:
+				ErrorBox("Unknown file extension or format of destination");
+				}
+			DeleteGO(go);
+			go = 0L;
+			}
+		break;
+		}
+	return true;
+}
+
+
+int Usage()
+{
+	printf("______________________________________________________________\n");
+	printf("\nexprlp: RLPlot export utility, version %s.\n", SZ_VERSION);
+	printf("Copyright (C) 2002-2005 R. Lackner\n");
+	printf("This is free software published under the GNU\n");
+	printf("general public licence (GPL).\n");
+	printf("\nUsage: exprlp [options] <input> [options] [<output>]\n");
+	printf("\nOptions:\n");
+	printf("   -      use stdin/stdout as input or output file; requires\n");
+	printf("             that file format is set by -e | -s | -w option\n");
+	printf("             not an option in the strict sense\n");
+	printf("   -h     print this information\n");
+	printf("   -d     delete input file after read\n");
+	printf("   -e     output Encapsulated PostScript, *.eps\n");
+	printf("   -s     output Scalable Vector Graphics, *.svg\n");
+	printf("   -S     like -s, start output with \"Content-Type: image/svg+xml\"\n");
+	printf("   -v     print RLPlot version\n");
+	printf("   -w     output Windows Meta File, *.wmf\n");
+	printf("   -q     quiet mode: suppress output to the console\n");
+	printf("\nExamples:\n");
+	printf("   exprlp foo.rlp foo.svg      ;exports Scalable Vector Graphics\n");
+	printf("   exprlp -q foo.rlp foo.eps   ;exports Encapsulated PostScript, no messages\n");
+	printf("   exprlp foo.rlp foo.wmf      ;exports Windows Meta File\n");
+	printf("   exprlp -sq foo.rlp -        ;exports SVG to the console, no messages\n");
+	printf("   exprlp -eq - -              ;converts inputfile from stdin to EPS\n");
+	printf("                                   on stdout: useful for pipes\n");
+	printf("\n switch character is either \'-\' or \'/\'\n");
+	printf("______________________________________________________________\n\n");
+	if(szFile1) free(szFile1);	if(szFile2) free(szFile2);
+	szFile1 = szFile2 = 0L;
+	return 1;
+}
+
+int main (int argc, char **argv)
+{
+	ExpRoot *base = 0L;
+	int i, j, k;
+
+	for (i = 1, j = 0; i < argc; i++) {
+		if(argv[i][0] == '-' || (argv[i][0] == '/' && strlen(argv[i]) < 5)) {
+			//check for switch
+			for(k = 1; argv[i][k-1]; k++) {
+				switch(argv[i][k]){
+				case 'h':	case 'H':	case '?':
+					return Usage();
+				case 'd':
+					bDelete = true;
+					break;
+				case 'S':
+					bSVGtype = true;
+				case 's':
+					file_fmt = FF_SVG;
+					break;
+				case 'e':	case 'E':
+					file_fmt = FF_EPS;
+					break;
 				case 'r':	case 'R':
 					file_fmt = FF_RLP;
 					break;
-				case 'w':	case 'W':
-					file_fmt = FF_WMF;
-					break;
-				case 'q':	case 'Q':
-					bQuiet = true;
-					break;
-				case 'v':	case 'V':
-					printf("RLPlot version %s\n", SZ_VERSION);
-					return 0;
-				case '\0':
-					if(k == 1) {
-						if(j == 0) szFile1 = strdup("-");
-						else if(j == 1) szFile2 = strdup("-");
-						j++;
-						}
-					break;
-					}
-				}
-			}
-		else switch(j) {
-		case 0:
-			szFile1 = strdup(argv[i]);
-			j++;
-			break;
-		case 1:
-			szFile2 = strdup(argv[i]);
-			j++;
-			}
-		}
-	if(file_fmt == FF_UNKNOWN && szFile2 && (i = strlen(szFile2)) > 4) {
-		if(0==strcmp(".svg", szFile2+i-4)) file_fmt = FF_SVG;
-		else if(0==strcmp(".wmf", szFile2+i-4)) file_fmt = FF_WMF;
-		else if(0==strcmp(".eps", szFile2+i-4)) file_fmt = FF_EPS;
+				case 'w':	case 'W':
+					file_fmt = FF_WMF;
+					break;
+				case 'q':	case 'Q':
+					bQuiet = true;
+					break;
+				case 'v':	case 'V':
+					printf("RLPlot version %s\n", SZ_VERSION);
+					return 0;
+				case '\0':
+					if(k == 1) {
+						if(j == 0) szFile1 = strdup("-");
+						else if(j == 1) szFile2 = strdup("-");
+						j++;
+						}
+					break;
+					}
+				}
+			}
+		else switch(j) {
+		case 0:
+			szFile1 = strdup(argv[i]);
+			j++;
+			break;
+		case 1:
+			szFile2 = strdup(argv[i]);
+			j++;
+			}
+		}
+	if(file_fmt == FF_UNKNOWN && szFile2 && (i = strlen(szFile2)) > 4) {
+		if(0==strcmp(".svg", szFile2+i-4)) file_fmt = FF_SVG;
+		else if(0==strcmp(".wmf", szFile2+i-4)) file_fmt = FF_WMF;
+		else if(0==strcmp(".eps", szFile2+i-4)) file_fmt = FF_EPS;
 		else if(0==strcmp(".rlp", szFile2+i-4)) file_fmt = FF_RLP;
-		}
-	if(file_fmt == FF_UNKNOWN) {
-		if(szFile1)printf("\n**** Unknown file extension or format ****\n\n");
-		return Usage();
-		}
-	if(!bQuiet) {
-		fprintf(stderr,"Input file \"%s\"\n", szFile1);
-		fprintf(stderr,"Output file \"%s\"\n", szFile2);
-		}
-	setlocale(LC_ALL, "");
-	if(!szFile1) return Usage();
-	base = new ExpRoot(szFile1, szFile2);
-	if(base) {
-		delete base;
-		}
-	if(szFile1) free(szFile1);	if(szFile2) free(szFile2);
-	return 0;
-}
+		}
+	if(file_fmt == FF_UNKNOWN) {
+		if(szFile1)printf("\n**** Unknown file extension or format ****\n\n");
+		return Usage();
+		}
+	if(!bQuiet) {
+		fprintf(stderr,"Input file \"%s\"\n", szFile1);
+		fprintf(stderr,"Output file \"%s\"\n", szFile2);
+		}
+	setlocale(LC_ALL, "");
+	if(!szFile1) return Usage();
+	base = new ExpRoot(szFile1, szFile2);
+	if(base) {
+		delete base;
+		}
+	if(szFile1) free(szFile1);	if(szFile2) free(szFile2);
+	return 0;
+}
diff --git a/menu.h b/menu.h
index 3146703..8e02c7f 100755
--- a/menu.h
+++ b/menu.h
@@ -92,6 +92,8 @@
 #define CM_SHPGUP      615
 #define CM_SHPGDOWN    616
 
-#define CM_REPANOV     650
-#define CM_REPREGR     651
-
+#define CM_REPCMEANS   650
+#define CM_REPANOV     651
+#define CM_REPREGR     652
+#define CM_REPTWOWAY   653
+
diff --git a/mfcalc.cpp b/mfcalc.cpp
index 3705bb6..9d20746 100644
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -9,48 +9,52 @@
 #define	STR	259
 #define	ARR	260
 #define	BLOCK	261
-#define	PI	262
-#define	E	263
-#define	CLVAL	264
-#define	PSEP	265
-#define	IF	266
-#define	ELSE	267
-#define	BTRUE	268
-#define	BFALSE	269
-#define	DATE1	270
-#define	TIME1	271
-#define	DATETIME1	272
-#define	DIM	273
-#define	VAR	274
-#define	FNCT	275
-#define	BFNCT	276
-#define	AFNCT	277
-#define	SFNCT	278
-#define	FUNC1	279
-#define	FUNC2	280
-#define	FUNC3	281
-#define	TXT	282
-#define	SRFUNC	283
-#define	YYFNC	284
-#define	FUNC4	285
-#define	CLAUSE	286
-#define	SER	287
-#define	COLR	288
-#define	COLC	289
-#define	AND	290
-#define	OR	291
-#define	EQ	292
-#define	NE	293
-#define	GT	294
-#define	GE	295
-#define	LT	296
-#define	LE	297
-#define	NEG	298
-#define	INC	299
-#define	DEC	300
-#define	PINC	301
-#define	PDEC	302
-#define	PDIM	303
+#define	PBLOCK	262
+#define	PI	263
+#define	E	264
+#define	CLVAL	265
+#define	PSEP	266
+#define	IF	267
+#define	ELSE	268
+#define	BTRUE	269
+#define	BFALSE	270
+#define	DATE1	271
+#define	TIME1	272
+#define	DATETIME1	273
+#define	DIM	274
+#define	WHILE	275
+#define	VAR	276
+#define	FNCT	277
+#define	BFNCT	278
+#define	AFNCT	279
+#define	SFNCT	280
+#define	FUNC1	281
+#define	FUNC2	282
+#define	FUNC3	283
+#define	TXT	284
+#define	SRFUNC	285
+#define	YYFNC	286
+#define	FUNC4	287
+#define	YYFNC2	288
+#define	YYFNC3	289
+#define	CLAUSE	290
+#define	SER	291
+#define	COLR	292
+#define	COLC	293
+#define	AND	294
+#define	OR	295
+#define	EQ	296
+#define	NE	297
+#define	GT	298
+#define	GE	299
+#define	LT	300
+#define	LE	301
+#define	NEG	302
+#define	INC	303
+#define	DEC	304
+#define	PINC	305
+#define	PDEC	306
+#define	PDIM	307
 
 
 /*
@@ -97,9 +101,10 @@ public:
         void SetValue(void* dest, void* src);
 	void SetName(char *nam);
 	void InitSS();
+	void NoInit();
 
 private:
-	bool isSSval;
+	bool isSSval, isValid;
 
 };
 
@@ -123,6 +128,8 @@ typedef struct{
 
 }YYSTYPE;
 
+static int yy_maxiter = 1000;
+
 static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
 static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
 static int push(YYSTYPE *res, YYSTYPE *val);
@@ -132,7 +139,7 @@ static double *PushArray(double *arr);
 static double *ReallocArray(double *arr, int size);
 static char *add_strings(char *st1, char *st2);
 static char *string_value(YYSTYPE *exp);
-static double eval(YYSTYPE *sr, YYSTYPE *dst, char* dum);
+static void eval(YYSTYPE *dst, YYSTYPE *sr);
 static int range_array(YYSTYPE * res, char *range);
 static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
@@ -163,23 +170,23 @@ static int parse_level = 0;		//count reentrances into parser
 
 
 
-#define	YYFINAL		222
+#define	YYFINAL		269
 #define	YYFLAG		-32768
-#define	YYNTBASE	65
+#define	YYNTBASE	69
 
-#define YYTRANSLATE(x) ((unsigned)(x) <= 303 ? yytranslate[x] : 72)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 307 ? yytranslate[x] : 76)
 
 static const char yytranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    59,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    63,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    61,
-    62,    49,    48,    33,    47,     2,    50,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,    64,    60,     2,
-    32,     2,    38,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    65,
+    66,    53,    52,    37,    51,     2,    54,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    68,    64,     2,
+    36,     2,    42,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-    51,     2,    63,    58,     2,     2,     2,     2,     2,     2,
+    55,     2,    67,    56,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -198,9 +205,9 @@ static const char yytranslate[] = {     0,
      2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
      7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
     17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-    27,    28,    29,    30,    31,    34,    35,    36,    37,    39,
-    40,    41,    42,    43,    44,    45,    46,    52,    53,    54,
-    55,    56,    57
+    27,    28,    29,    30,    31,    32,    33,    34,    35,    38,
+    39,    40,    41,    43,    44,    45,    46,    47,    48,    49,
+    50,    57,    58,    59,    60,    61,    62
 };
 
 #if YYDEBUG != 0
@@ -212,72 +219,84 @@ static const short yyprhs[] = {     0,
    142,   144,   146,   148,   150,   152,   154,   156,   158,   162,
    166,   171,   176,   183,   192,   197,   202,   209,   216,   223,
    230,   237,   244,   251,   258,   265,   274,   281,   290,   301,
-   308,   312,   317,   323,   331,   335,   339,   343,   347,   350,
-   353,   356,   359,   362,   366,   370,   376,   381,   388,   394,
-   400,   404,   408,   414,   420,   426
+   308,   312,   317,   324,   331,   338,   345,   354,   363,   372,
+   381,   390,   399,   408,   417,   423,   431,   435,   439,   443,
+   447,   451,   454,   457,   460,   463,   467,   470,   474,   480,
+   485,   492,   498,   504,   508,   512,   518,   524,   530
 };
 
 static const short yyrhs[] = {    -1,
-    65,    66,     0,    59,     0,    60,     0,    33,     0,    71,
-    59,     0,    71,    60,     0,    71,    33,     0,    67,    59,
-     0,    67,    60,     0,     1,    59,     0,     5,     0,    67,
-    48,    71,     0,    71,    48,    67,     0,    67,    48,    67,
-     0,    29,    61,    71,    62,     0,    29,    61,    71,    11,
-    67,    62,     0,    29,    61,    71,    11,    71,    62,     0,
-    29,    61,    71,    33,    67,    62,     0,    29,    61,    71,
-    33,    71,    62,     0,    67,     0,    20,    36,    20,     0,
-     6,     0,    71,     0,    69,    33,    69,     0,    69,    34,
-    71,     0,    68,     0,     3,    35,     3,     0,     4,     0,
-    22,    61,    71,    62,     0,    14,     0,    15,     0,    71,
-    39,    71,     0,    71,    40,    71,     0,    71,    41,    71,
-     0,    71,    42,    71,     0,    71,    43,    71,     0,    71,
-    44,    71,     0,    71,    45,    71,     0,    71,    46,    71,
-     0,     3,     0,    70,     0,    28,     0,    10,     0,     8,
-     0,     9,     0,    20,     0,     7,     0,    20,    32,    71,
-     0,    20,    32,    67,     0,    21,    61,    71,    62,     0,
-    23,    61,    69,    62,     0,    23,    61,    71,    11,    69,
-    62,     0,    23,    61,    71,    11,    71,    11,    71,    62,
-     0,    24,    61,    67,    62,     0,    24,    61,    71,    62,
-     0,    24,    61,    67,    11,    67,    62,     0,    24,    61,
-    71,    11,    67,    62,     0,    24,    61,    71,    11,    71,
-    62,     0,    24,    61,    67,    11,    71,    62,     0,    24,
-    61,    67,    33,    67,    62,     0,    24,    61,    71,    33,
-    67,    62,     0,    24,    61,    67,    33,    71,    62,     0,
-    24,    61,    71,    33,    71,    62,     0,    26,    61,    68,
-    11,    68,    62,     0,    26,    61,    68,    11,    68,    11,
-    68,    62,     0,    27,    61,    69,    11,    69,    62,     0,
-    27,    61,    69,    11,    69,    11,    68,    62,     0,    31,
-    61,    71,    11,    71,    11,    69,    11,    68,    62,     0,
-    25,    61,    69,    11,    68,    62,     0,    30,    61,    62,
-     0,    30,    61,    69,    62,     0,    12,    61,    71,    62,
-     7,     0,    12,    61,    71,    62,     7,    13,     7,     0,
-    71,    48,    71,     0,    71,    47,    71,     0,    71,    49,
-    71,     0,    71,    50,    71,     0,    47,    71,     0,    20,
-    53,     0,    20,    54,     0,    53,    20,     0,    54,    20,
-     0,    71,    58,    71,     0,    61,    69,    62,     0,    19,
-    20,    51,    71,    63,     0,    71,    51,    71,    63,     0,
-    71,    51,    71,    63,    32,    71,     0,     3,    36,     3,
-    36,     3,     0,     3,    64,     3,    64,     3,     0,     3,
-    36,     3,     0,     3,    64,     3,     0,    71,    38,    71,
-    37,    71,     0,    71,    38,     5,    37,     5,     0,    71,
-    38,     5,    37,    71,     0,    71,    38,    71,    37,     5,
-     0
+    69,    70,     0,    63,     0,    64,     0,    37,     0,    75,
+    63,     0,    75,    64,     0,    75,    37,     0,    71,    63,
+     0,    71,    64,     0,     1,    63,     0,     5,     0,    71,
+    52,    75,     0,    75,    52,    71,     0,    71,    52,    71,
+     0,    31,    65,    75,    66,     0,    31,    65,    75,    12,
+    71,    66,     0,    31,    65,    75,    12,    75,    66,     0,
+    31,    65,    75,    37,    71,    66,     0,    31,    65,    75,
+    37,    75,    66,     0,    71,     0,    22,    40,    22,     0,
+     6,     0,    75,     0,    73,    37,    73,     0,    73,    38,
+    75,     0,    72,     0,     3,    39,     3,     0,     4,     0,
+    24,    65,    75,    66,     0,    15,     0,    16,     0,    75,
+    43,    75,     0,    75,    44,    75,     0,    75,    45,    75,
+     0,    75,    46,    75,     0,    75,    47,    75,     0,    75,
+    48,    75,     0,    75,    49,    75,     0,    75,    50,    75,
+     0,     3,     0,    74,     0,    30,     0,    11,     0,     9,
+     0,    10,     0,    22,     0,     7,     0,    22,    36,    75,
+     0,    22,    36,    71,     0,    23,    65,    75,    66,     0,
+    25,    65,    73,    66,     0,    25,    65,    75,    12,    73,
+    66,     0,    25,    65,    75,    12,    75,    12,    75,    66,
+     0,    26,    65,    71,    66,     0,    26,    65,    75,    66,
+     0,    26,    65,    71,    12,    71,    66,     0,    26,    65,
+    75,    12,    71,    66,     0,    26,    65,    75,    12,    75,
+    66,     0,    26,    65,    71,    12,    75,    66,     0,    26,
+    65,    71,    37,    71,    66,     0,    26,    65,    75,    37,
+    71,    66,     0,    26,    65,    71,    37,    75,    66,     0,
+    26,    65,    75,    37,    75,    66,     0,    28,    65,    72,
+    12,    72,    66,     0,    28,    65,    72,    12,    72,    12,
+    72,    66,     0,    29,    65,    73,    12,    73,    66,     0,
+    29,    65,    73,    12,    73,    12,    72,    66,     0,    33,
+    65,    75,    12,    75,    12,    73,    12,    72,    66,     0,
+    27,    65,    73,    12,    72,    66,     0,    32,    65,    66,
+     0,    32,    65,    73,    66,     0,    34,    65,    75,    12,
+    75,    66,     0,    34,    65,    71,    12,    75,    66,     0,
+    34,    65,    75,    12,    71,    66,     0,    34,    65,    71,
+    12,    71,    66,     0,    35,    65,    71,    12,    71,    12,
+    71,    66,     0,    35,    65,    75,    12,    71,    12,    71,
+    66,     0,    35,    65,    71,    12,    75,    12,    71,    66,
+     0,    35,    65,    71,    12,    71,    12,    75,    66,     0,
+    35,    65,    75,    12,    75,    12,    71,    66,     0,    35,
+    65,    75,    12,    71,    12,    75,    66,     0,    35,    65,
+    71,    12,    75,    12,    75,    66,     0,    35,    65,    75,
+    12,    75,    12,    75,    66,     0,    13,    65,    75,    66,
+     7,     0,    13,    65,    75,    66,     7,    14,     7,     0,
+    21,     8,     7,     0,    75,    52,    75,     0,    75,    51,
+    75,     0,    75,    53,    75,     0,    75,    54,    75,     0,
+    22,    58,     0,    22,    59,     0,    58,    22,     0,    59,
+    22,     0,    75,    56,    75,     0,    51,    75,     0,    65,
+    73,    66,     0,    20,    22,    55,    75,    67,     0,    75,
+    55,    75,    67,     0,    75,    55,    75,    67,    36,    75,
+     0,     3,    40,     3,    40,     3,     0,     3,    68,     3,
+    68,     3,     0,     3,    40,     3,     0,     3,    68,     3,
+     0,    75,    42,    75,    41,    75,     0,    75,    42,     5,
+    41,     5,     0,    75,    42,     5,    41,    75,     0,    75,
+    42,    75,    41,     5,     0
 };
 
 #endif
 
 #if YYDEBUG != 0
 static const short yyrline[] = { 0,
-   128,   129,   132,   132,   132,   133,   134,   135,   136,   137,
-   138,   141,   143,   144,   145,   146,   147,   148,   149,   150,
-   153,   155,   159,   160,   161,   162,   163,   164,   168,   169,
-   170,   171,   172,   173,   174,   175,   176,   177,   178,   179,
-   182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
-   192,   193,   194,   196,   199,   200,   201,   202,   203,   204,
-   205,   206,   207,   208,   209,   210,   211,   212,   213,   214,
-   215,   216,   217,   218,   219,   223,   227,   228,   230,   231,
-   232,   233,   234,   235,   236,   237,   239,   241,   243,   244,
-   245,   246,   247,   248,   249,   250
+   132,   133,   136,   136,   136,   137,   138,   139,   140,   141,
+   142,   145,   147,   148,   149,   150,   151,   152,   153,   154,
+   157,   159,   163,   164,   165,   166,   167,   168,   172,   173,
+   174,   175,   176,   177,   178,   179,   180,   181,   182,   183,
+   186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
+   196,   197,   198,   200,   203,   204,   205,   206,   207,   208,
+   209,   210,   211,   212,   213,   214,   215,   216,   217,   218,
+   219,   220,   221,   222,   223,   224,   225,   226,   227,   228,
+   229,   230,   231,   232,   233,   234,   235,   239,   243,   247,
+   248,   250,   251,   252,   253,   254,   255,   256,   257,   259,
+   261,   263,   264,   265,   266,   267,   268,   269,   270
 };
 #endif
 
@@ -285,26 +304,28 @@ static const short yyrline[] = { 0,
 #if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
 
 static const char * const yytname[] = {   "$","error","$undefined.","NUM","BOOLVAL",
-"STR","ARR","BLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE","BFALSE","DATE1",
-"TIME1","DATETIME1","DIM","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","FUNC2",
-"FUNC3","TXT","SRFUNC","YYFNC","FUNC4","'='","','","CLAUSE","SER","COLR","COLC",
-"'?'","AND","OR","EQ","NE","GT","GE","LT","LE","'-'","'+'","'*'","'/'","'['",
-"NEG","INC","DEC","PINC","PDEC","PDIM","'^'","'\\n'","';'","'('","')'","']'",
-"':'","input","line","str_exp","range","arr","bool","exp", NULL
+"STR","ARR","BLOCK","PBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE","BFALSE",
+"DATE1","TIME1","DATETIME1","DIM","WHILE","VAR","FNCT","BFNCT","AFNCT","SFNCT",
+"FUNC1","FUNC2","FUNC3","TXT","SRFUNC","YYFNC","FUNC4","YYFNC2","YYFNC3","'='",
+"','","CLAUSE","SER","COLR","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT",
+"LE","'-'","'+'","'*'","'/'","'['","'^'","NEG","INC","DEC","PINC","PDEC","PDIM",
+"'\\n'","';'","'('","')'","']'","':'","input","line","str_exp","range","arr",
+"bool","exp", NULL
 };
 #endif
 
 static const short yyr1[] = {     0,
-    65,    65,    66,    66,    66,    66,    66,    66,    66,    66,
-    66,    67,    67,    67,    67,    67,    67,    67,    67,    67,
-    68,    68,    69,    69,    69,    69,    69,    69,    70,    70,
-    70,    70,    70,    70,    70,    70,    70,    70,    70,    70,
-    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    71,    71,    71,    71,    71,    71
+    69,    69,    70,    70,    70,    70,    70,    70,    70,    70,
+    70,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    72,    72,    73,    73,    73,    73,    73,    73,    74,    74,
+    74,    74,    74,    74,    74,    74,    74,    74,    74,    74,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+    75,    75,    75,    75,    75,    75,    75,    75,    75
 };
 
 static const short yyr2[] = {     0,
@@ -315,295 +336,358 @@ static const short yyr2[] = {     0,
      1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
      4,     4,     6,     8,     4,     4,     6,     6,     6,     6,
      6,     6,     6,     6,     6,     8,     6,     8,    10,     6,
-     3,     4,     5,     7,     3,     3,     3,     3,     2,     2,
-     2,     2,     2,     3,     3,     5,     4,     6,     5,     5,
-     3,     3,     5,     5,     5,     5
+     3,     4,     6,     6,     6,     6,     8,     8,     8,     8,
+     8,     8,     8,     8,     5,     7,     3,     3,     3,     3,
+     3,     2,     2,     2,     2,     3,     2,     3,     5,     4,
+     6,     5,     5,     3,     3,     5,     5,     5,     5
 };
 
 static const short yydefact[] = {     1,
      0,     0,    41,    29,    12,    48,    45,    46,    44,     0,
-    31,    32,     0,    47,     0,     0,     0,     0,     0,     0,
-     0,    43,     0,     0,     0,     5,     0,     0,     0,     3,
-     4,     0,     2,     0,    42,     0,    11,     0,     0,     0,
-     0,     0,    80,    81,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,    79,    82,    83,    41,    23,    47,
-    21,    27,     0,    24,     0,     9,    10,     8,     0,     0,
+    31,    32,     0,     0,    47,     0,     0,     0,     0,     0,
+     0,     0,    43,     0,     0,     0,     0,     0,     5,     0,
+     0,     0,     3,     4,     0,     2,     0,    42,     0,    11,
+     0,     0,     0,     0,     0,     0,    92,    93,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+    97,    94,    95,    41,    23,    47,    21,    27,     0,    24,
+     0,     9,    10,     8,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     6,
+     7,   104,   105,     0,     0,    87,    50,    49,     0,     0,
+     0,    24,     0,     0,     0,     0,     0,     0,     0,    71,
      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     6,     7,    91,    92,     0,     0,    50,
-    49,     0,     0,     0,    24,     0,     0,     0,     0,     0,
-     0,     0,    71,     0,     0,     0,     0,     0,     0,     0,
-    85,    15,    13,     0,     0,    33,    34,    35,    36,    37,
-    38,    39,    40,    76,    14,    75,    77,    78,     0,    84,
-     0,     0,     0,     0,    51,    30,    52,     0,     0,     0,
-    55,     0,     0,    56,     0,     0,     0,     0,     0,    16,
-    72,     0,    75,    28,    22,    25,    26,     0,     0,    87,
-    89,    90,    73,    86,     0,    24,     0,     0,     0,     0,
+     0,    98,    15,    13,     0,     0,    33,    34,    35,    36,
+    37,    38,    39,    40,    89,    14,    88,    90,    91,     0,
+    96,     0,     0,     0,     0,    51,    30,    52,     0,     0,
+     0,    55,     0,     0,    56,     0,     0,     0,     0,     0,
+    16,    72,     0,     0,     0,     0,     0,    88,    28,    22,
+    25,    26,     0,     0,   100,   102,   103,    85,    99,     0,
+    24,     0,     0,     0,     0,     0,     0,     0,     0,     0,
      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,    94,    95,    96,    93,     0,     0,    53,     0,
-    57,    60,    61,    63,    58,    59,    62,    64,    70,     0,
-    65,     0,    67,    17,    18,    19,    20,     0,    88,    74,
-     0,     0,     0,     0,    54,    66,    68,     0,     0,    69,
-     0,     0
+     0,     0,     0,     0,     0,   107,   108,   109,   106,     0,
+     0,    53,     0,    57,    60,    61,    63,    58,    59,    62,
+    64,    70,     0,    65,     0,    67,    17,    18,    19,    20,
+     0,    76,    74,    75,    73,     0,     0,     0,     0,   101,
+    86,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,    54,    66,    68,     0,    77,    80,    79,
+    83,    78,    82,    81,    84,     0,    69,     0,     0
 };
 
 static const short yydefgoto[] = {     1,
-    33,    61,    62,    63,    35,    64
+    36,    67,    68,    69,    38,    70
 };
 
 static const short yypact[] = {-32768,
-   204,   -44,   -26,-32768,-32768,-32768,-32768,-32768,-32768,   -45,
--32768,-32768,     5,    33,   -42,   -25,     6,    22,    24,    32,
-    39,-32768,    41,    49,    54,-32768,   646,    36,    38,-32768,
--32768,   323,-32768,   105,-32768,   799,-32768,    14,    57,   646,
-    10,   378,-32768,-32768,   646,   646,   323,   378,   323,   433,
-   323,   646,   263,   646,     8,-32768,-32768,   -27,-32768,    63,
-    55,-32768,   -20,   994,   378,-32768,-32768,-32768,   488,   646,
-   646,   646,   646,   646,   646,   646,   646,   646,   378,   646,
-   646,   646,   646,-32768,-32768,    83,    76,   372,   646,    55,
-   994,   427,   482,   -12,    85,     0,   670,     1,   111,   994,
-    78,   711,-32768,   -10,   736,   646,   146,   130,   323,   646,
--32768,-32768,   129,   118,   973,   197,   197,   125,   125,   125,
-   125,   125,   125,   129,-32768,   129,   -31,   -31,   257,     8,
-   153,   156,   154,   317,-32768,-32768,-32768,   323,   378,   378,
--32768,   378,   378,-32768,   433,   433,   323,   378,   378,-32768,
--32768,   646,   129,-32768,-32768,   132,  1015,   543,   598,   131,
--32768,-32768,   155,-32768,    -3,   757,   -30,   537,    -8,   822,
-    46,   847,    56,   872,   107,    -7,    -5,    58,   897,    98,
-   922,   778,-32768,  1015,-32768,  1015,   646,   160,-32768,   646,
--32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,   433,
--32768,   433,-32768,-32768,-32768,-32768,-32768,   323,  1015,-32768,
-   947,   109,   115,    80,-32768,-32768,-32768,   433,   126,-32768,
-   192,-32768
+   242,   -55,    -3,-32768,-32768,-32768,-32768,-32768,-32768,   -52,
+-32768,-32768,    -7,     9,    70,   -44,   -42,   -33,     4,     6,
+     7,    28,-32768,    31,    47,    52,    73,    95,-32768,   707,
+    41,    93,-32768,-32768,   369,-32768,    50,-32768,   822,-32768,
+   131,   158,   707,   112,   162,   426,-32768,-32768,   707,   707,
+   369,   426,   369,   483,   369,   707,   305,   707,   426,   426,
+-32768,-32768,-32768,   -30,-32768,    65,   118,-32768,   -26,   363,
+   426,-32768,-32768,-32768,   540,   707,   707,   707,   707,   707,
+   707,   707,   707,   707,   426,   707,   707,   707,   707,-32768,
+-32768,   159,   103,   871,   707,-32768,   118,   363,   896,   921,
+   -19,   135,    -6,   731,    54,   163,   363,    61,   757,-32768,
+    -4,   420,   -11,   477,    -9,   534,   707,   195,   181,   369,
+   707,-32768,-32768,    86,   165,  1272,   699,   699,   141,   141,
+   141,   141,   141,   141,    86,-32768,    86,    12,    12,   299,
+-32768,   204,   210,   207,   845,-32768,-32768,-32768,   369,   426,
+   426,-32768,   426,   426,-32768,   483,   483,   369,   426,   426,
+-32768,-32768,   707,   426,   426,   426,   426,    86,-32768,-32768,
+   182,  1287,   597,   654,   183,-32768,-32768,   209,-32768,    -2,
+   591,   -36,   946,   -27,   971,    38,   996,    43,  1021,   155,
+    -5,   -10,    67,  1046,    69,  1071,   648,    78,  1096,    79,
+  1121,    -8,   783,     2,   802,-32768,  1287,-32768,  1287,   707,
+   218,-32768,   707,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,   483,-32768,   483,-32768,-32768,-32768,-32768,-32768,
+   369,-32768,-32768,-32768,-32768,   426,   426,   426,   426,  1287,
+-32768,  1146,   160,   161,    88,    80,  1171,    85,  1196,    91,
+  1221,   102,  1246,-32768,-32768,-32768,   483,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,   164,-32768,   228,-32768
 };
 
 static const short yypgoto[] = {-32768,
--32768,    42,   -48,   -46,-32768,    -1
+-32768,    51,   -49,   -31,-32768,    -1
 };
 
 
-#define	YYLAST		1073
-
-
-static const short yytable[] = {    36,
-    94,    99,    98,   200,   101,   202,   104,   107,    38,    38,
-   139,   145,   109,   110,    37,    40,    86,    65,    45,    82,
-   109,   110,   109,   110,    41,    55,    83,   109,   110,   109,
-   110,   191,   140,   109,   110,    46,    39,    39,    88,    65,
-    91,   111,    34,    92,    93,    95,    97,    65,   100,   137,
-   102,   151,   105,   193,   201,    56,   203,    57,   189,    87,
-    89,   141,   156,   113,    42,    83,    47,   115,   116,   117,
-   118,   119,   120,   121,   122,   123,   124,   126,   127,   128,
-   129,   130,    48,    90,    49,    43,    44,   134,   147,    96,
-   218,   165,    50,    65,    42,   138,   175,   176,   108,    51,
-   177,    52,    65,    65,   153,    65,   112,   195,   157,    53,
-   109,   110,   109,   110,    54,    43,    44,   197,   131,   204,
-   125,   146,    69,    70,    71,    72,    73,    74,    75,    76,
-    77,    78,    79,    80,    81,    82,   166,   168,   170,   132,
-   172,   174,    83,   100,   100,    65,   179,   181,   154,   155,
-   182,   212,    65,   213,   158,   161,   184,   186,   162,   206,
-   163,   214,   187,    66,    67,   110,   210,   188,   199,   219,
-   216,    78,   106,    80,    81,    82,   217,    80,    81,    82,
-   167,   169,    83,   171,   173,   209,    83,   220,   211,   178,
-   180,   222,     0,     0,     0,     0,     0,     0,   100,     0,
-   100,     0,     0,   221,     2,     0,     3,     4,     5,     0,
-     6,     7,     8,     9,     0,    10,   100,    11,    12,     0,
-     0,     0,    13,    14,    15,    16,    17,    18,    19,    20,
-    21,    22,    23,    24,    25,     0,    26,    72,    73,    74,
-    75,    76,    77,    78,   106,    80,    81,    82,     0,     0,
-    27,     0,     0,     0,    83,     0,    28,    29,     0,     0,
-     0,     0,    30,    31,    32,    58,     4,     5,    59,     6,
-     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
-     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
-    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
-     0,     0,     0,     0,    83,    28,    29,     0,     0,   160,
-     0,     0,     0,    32,   103,    58,     4,     5,    59,     6,
-     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
-     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
-    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
-     0,     0,     0,     0,    83,    28,    29,     0,     0,   164,
-     3,     4,     5,    32,     6,     7,     8,     9,     0,    10,
-     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
-    17,    18,    19,    20,    21,    22,    23,    24,    25,    69,
-    70,    71,    72,    73,    74,    75,    76,    77,    78,   106,
-    80,    81,    82,     0,    27,     0,     0,     0,     0,    83,
-    28,    29,     0,   133,     0,     3,     4,     5,    32,     6,
-     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
-     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
-    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
-     0,     0,     0,     0,    83,    28,    29,     0,   135,     0,
-     3,     4,   114,    32,     6,     7,     8,     9,     0,    10,
-     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
-    17,    18,    19,    20,    21,    22,     0,    24,    25,    69,
-    70,    71,    72,    73,    74,    75,    76,    77,    78,   106,
-    80,    81,    82,     0,    27,     0,     0,     0,     0,    83,
-    28,    29,     0,   136,     0,     3,     4,   183,    32,     6,
-     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
+#define	YYLAST		1343
+
+
+static const short yytable[] = {    39,
+   164,   225,   166,   236,   106,   150,   223,    40,   118,    41,
+   120,   121,    43,   238,    44,    71,    45,   120,   121,   101,
+    49,   105,    50,   108,    71,   111,   120,   121,    61,   214,
+   151,    51,   120,   121,   120,   121,    41,    42,   216,   122,
+    71,    94,    71,    71,    98,    71,   148,    99,   100,   102,
+   104,    37,   107,    71,   109,   226,   112,   114,   116,   152,
+   224,   162,    62,   212,    42,   156,    88,    89,    52,   124,
+    53,    54,   158,   126,   127,   128,   129,   130,   131,   132,
+   133,   134,   135,   137,   138,   139,   140,   141,   171,    71,
+   120,   121,    55,   145,    71,    56,    97,   120,   121,   257,
+    46,    71,   103,   218,   119,    46,   190,   191,   220,   113,
+   115,    57,    72,    73,    63,   168,    58,   180,    71,   172,
+    71,   123,    47,    48,   120,   121,   192,    47,    48,    71,
+    71,    71,   227,    92,   229,   136,    71,    59,    86,    87,
+    88,    89,    71,   232,   234,   258,   149,   181,   183,   185,
+   260,   187,   189,    71,   107,   107,   262,   194,   196,    60,
+    93,   197,   199,   201,   203,   205,    95,   264,    96,    71,
+   143,   207,   209,   243,   157,   244,    75,    76,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+    89,    84,   117,    86,    87,    88,    89,   169,   142,   245,
+   182,   184,   170,   186,   188,   173,   176,   266,   240,   193,
+   195,   242,   177,   178,   198,   200,   202,   204,   210,   121,
+   222,   107,   211,   107,   241,   255,   256,   269,     0,   267,
+     0,     0,     0,     0,   247,   249,   251,   253,     0,     0,
+     0,   268,     2,     0,     3,     4,     5,     0,     6,     0,
+     7,     8,     9,     0,    10,   107,    11,    12,     0,     0,
      0,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-    22,     0,    24,    25,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,    79,    80,    81,    82,     0,    27,
-     0,     0,     0,     0,    83,    28,    29,     0,   192,     0,
-     3,     4,   185,    32,     6,     7,     8,     9,     0,    10,
+    22,    23,    24,    25,    26,    27,    28,     0,    29,     0,
+     0,     0,     0,     0,     0,     0,   246,   248,   250,   252,
+     0,     0,    30,     0,     0,     0,     0,     0,     0,    31,
+    32,     0,     0,     0,    33,    34,    35,    64,     4,     5,
+    65,     6,     0,     7,     8,     9,     0,    10,     0,    11,
+    12,     0,     0,     0,    13,    14,    66,    16,    17,    18,
+    19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+    75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+   117,    86,    87,    88,    89,    30,     0,     0,     0,     0,
+     0,     0,    31,    32,     0,   175,     0,     0,     0,    35,
+   110,    64,     4,     5,    65,     6,     0,     7,     8,     9,
+     0,    10,     0,    11,    12,     0,     0,     0,    13,    14,
+    66,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+    25,    26,    27,    28,    75,    76,    77,    78,    79,    80,
+    81,    82,    83,    84,    85,    86,    87,    88,    89,    30,
+     0,     0,     0,     0,     0,     0,    31,    32,     3,     4,
+     5,   163,     6,    35,     7,     8,     9,     0,    10,     0,
+    11,    12,     0,     0,     0,    13,    14,    15,    16,    17,
+    18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    75,    76,    77,    78,    79,    80,    81,    82,    83,
+    84,   117,    86,    87,    88,    89,    30,     0,     0,     0,
+     0,     0,     0,    31,    32,     3,     4,     5,   165,     6,
+    35,     7,     8,     9,     0,    10,     0,    11,    12,     0,
+     0,     0,    13,    14,    66,    16,    17,    18,    19,    20,
+    21,    22,    23,    24,    25,    26,    27,    28,    75,    76,
+    77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+    87,    88,    89,    30,     0,     0,     0,     0,     0,     0,
+    31,    32,     3,     4,   125,   167,     6,    35,     7,     8,
+     9,     0,    10,     0,    11,    12,     0,     0,     0,    13,
+    14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+     0,    25,    26,    27,    28,    75,    76,    77,    78,    79,
+    80,    81,    82,    83,    84,    85,    86,    87,    88,    89,
+    30,     0,     0,     0,     0,     0,     0,    31,    32,     3,
+     4,   206,   213,     6,    35,     7,     8,     9,     0,    10,
      0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
-    17,    18,    19,    20,    21,    22,     0,    24,    25,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,    27,     0,     0,     0,     3,     4,
-    28,    29,     6,     7,     8,     9,     0,    10,    32,    11,
-    12,     0,     0,     0,    13,    14,    15,    16,    17,    18,
-    19,    20,    21,    22,     0,    24,    25,     0,     0,     0,
-   142,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,    27,     0,     0,     0,     0,     0,    28,    29,
-     0,     0,   143,     0,     0,     0,    32,    69,    70,    71,
-    72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
-    82,   148,     0,     0,     0,     0,     0,    83,     0,     0,
-     0,   144,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   149,     0,     0,   152,     0,    69,    70,
-    71,    72,    73,    74,    75,    76,    77,    78,   106,    80,
-    81,    82,     0,     0,     0,     0,     0,   190,    83,     0,
-     0,     0,   150,    69,    70,    71,    72,    73,    74,    75,
-    76,    77,    78,   106,    80,    81,    82,     0,   208,     0,
-     0,     0,     0,    83,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
-     0,     0,     0,     0,    83,    69,    70,    71,    72,    73,
-    74,    75,    76,    77,    78,   106,    80,    81,    82,     0,
-     0,    68,     0,     0,     0,    83,    69,    70,    71,    72,
-    73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
-     0,     0,     0,     0,     0,     0,    83,    84,    85,    69,
-    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
-    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
-     0,     0,     0,   194,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
-     0,     0,     0,     0,    83,     0,     0,     0,   196,    69,
-    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
-    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
-     0,     0,     0,   198,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
-     0,     0,     0,     0,    83,     0,     0,     0,   205,    69,
-    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
-    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
-     0,     0,     0,   207,    69,    70,    71,    72,    73,    74,
-    75,    76,    77,    78,   106,    80,    81,    82,     0,     0,
-     0,     0,     0,     0,    83,     0,     0,     0,   215,   159,
-    69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
-   106,    80,    81,    82,     0,     0,     0,     0,     0,     0,
-    83,    69,    70,    71,    72,    73,    74,    75,    76,    77,
-    78,    79,    80,    81,    82,     0,     0,     0,     0,     0,
-     0,    83,    69,    70,    71,    72,    73,    74,    75,    76,
-    77,    78,   106,    80,    81,    82,     0,     0,     0,     0,
-     0,     0,    83
+    17,    18,    19,    20,    21,    22,    23,     0,    25,    26,
+    27,    28,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,    30,     0,     0,
+     0,     0,     0,     0,    31,    32,     3,     4,   208,   231,
+     6,    35,     7,     8,     9,     0,    10,     0,    11,    12,
+     0,     0,     0,    13,    14,    15,    16,    17,    18,    19,
+    20,    21,    22,    23,     0,    25,    26,    27,    28,    75,
+    76,    77,    78,    79,    80,    81,    82,    83,    84,   117,
+    86,    87,    88,    89,    30,     0,     0,     0,     0,     3,
+     4,    31,    32,     6,     0,     7,     8,     9,    35,    10,
+     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,    23,     0,    25,    26,
+    27,    28,   153,    78,    79,    80,    81,    82,    83,    84,
+   117,    86,    87,    88,    89,     0,     0,    30,     0,     0,
+     0,     0,     0,     0,    31,    32,     0,   154,   159,     0,
+     0,    35,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,   160,   237,     0,   155,     0,    75,    76,
+    77,    78,    79,    80,    81,    82,    83,    84,   117,    86,
+    87,    88,    89,   239,     0,     0,     0,     0,     0,     0,
+     0,     0,   161,     0,    75,    76,    77,    78,    79,    80,
+    81,    82,    83,    84,    85,    86,    87,    88,    89,     0,
+     0,     0,     0,    75,    76,    77,    78,    79,    80,    81,
+    82,    83,    84,    85,    86,    87,    88,    89,    74,     0,
+     0,     0,     0,    75,    76,    77,    78,    79,    80,    81,
+    82,    83,    84,    85,    86,    87,    88,    89,     0,     0,
+     0,     0,     0,     0,    90,    91,    75,    76,    77,    78,
+    79,    80,    81,    82,    83,    84,   117,    86,    87,    88,
+    89,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   179,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,   117,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   144,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,   117,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   146,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,   117,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   147,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   215,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   217,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   219,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   221,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   228,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   230,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   233,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   235,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,   117,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   254,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   259,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   261,    75,    76,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,   263,    75,    76,    77,
+    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
+    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   265,   174,    75,    76,    77,    78,    79,    80,    81,
+    82,    83,    84,   117,    86,    87,    88,    89,    75,    76,
+    77,    78,    79,    80,    81,    82,    83,    84,   117,    86,
+    87,    88,    89
 };
 
 static const short yycheck[] = {     1,
-    47,    50,    49,    11,    51,    11,    53,    35,    36,    36,
-    11,    11,    33,    34,    59,    61,     3,    48,    61,    51,
-    33,    34,    33,    34,    20,    27,    58,    33,    34,    33,
-    34,    62,    33,    33,    34,    61,    64,    64,    40,    48,
-    42,    62,     1,    45,    46,    47,    48,    48,    50,    62,
-    52,    62,    54,    62,    62,    20,    62,    20,    62,     3,
-    51,    62,   109,    65,    32,    58,    61,    69,    70,    71,
-    72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
-    82,    83,    61,    42,    61,    53,    54,    89,    11,    48,
-    11,   138,    61,    48,    32,    11,   145,   146,    36,    61,
-   147,    61,    48,    48,   106,    48,    65,    62,   110,    61,
-    33,    34,    33,    34,    61,    53,    54,    62,    36,    62,
-    79,    11,    38,    39,    40,    41,    42,    43,    44,    45,
-    46,    47,    48,    49,    50,    51,   138,   139,   140,    64,
-   142,   143,    58,   145,   146,    48,   148,   149,     3,    20,
-   152,   200,    48,   202,    37,     3,   158,   159,     3,    62,
-     7,   208,    32,    59,    60,    34,     7,    13,    62,   218,
-    62,    47,    48,    49,    50,    51,    62,    49,    50,    51,
-   139,   140,    58,   142,   143,   187,    58,    62,   190,   148,
-   149,     0,    -1,    -1,    -1,    -1,    -1,    -1,   200,    -1,
-   202,    -1,    -1,     0,     1,    -1,     3,     4,     5,    -1,
-     7,     8,     9,    10,    -1,    12,   218,    14,    15,    -1,
-    -1,    -1,    19,    20,    21,    22,    23,    24,    25,    26,
-    27,    28,    29,    30,    31,    -1,    33,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
-    47,    -1,    -1,    -1,    58,    -1,    53,    54,    -1,    -1,
-    -1,    -1,    59,    60,    61,     3,     4,     5,     6,     7,
-     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
-    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
-    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    -1,    63,
-    -1,    -1,    -1,    61,    62,     3,     4,     5,     6,     7,
-     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
-    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
-    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    -1,    63,
-     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
-    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
-    23,    24,    25,    26,    27,    28,    29,    30,    31,    38,
-    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    -1,    47,    -1,    -1,    -1,    -1,    58,
-    53,    54,    -1,    62,    -1,     3,     4,     5,    61,     7,
-     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
-    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
-    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    62,    -1,
-     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
-    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
-    23,    24,    25,    26,    27,    28,    -1,    30,    31,    38,
-    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    -1,    47,    -1,    -1,    -1,    -1,    58,
-    53,    54,    -1,    62,    -1,     3,     4,     5,    61,     7,
-     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
-    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    -1,    30,    31,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
-    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    62,    -1,
-     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
-    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
-    23,    24,    25,    26,    27,    28,    -1,    30,    31,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    47,    -1,    -1,    -1,     3,     4,
-    53,    54,     7,     8,     9,    10,    -1,    12,    61,    14,
-    15,    -1,    -1,    -1,    19,    20,    21,    22,    23,    24,
-    25,    26,    27,    28,    -1,    30,    31,    -1,    -1,    -1,
-    11,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    47,    -1,    -1,    -1,    -1,    -1,    53,    54,
-    -1,    -1,    33,    -1,    -1,    -1,    61,    38,    39,    40,
-    41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
-    51,    11,    -1,    -1,    -1,    -1,    -1,    58,    -1,    -1,
-    -1,    62,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    33,    -1,    -1,    11,    -1,    38,    39,
-    40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    -1,    -1,    -1,    -1,    -1,    11,    58,    -1,
-    -1,    -1,    62,    38,    39,    40,    41,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    -1,    11,    -1,
-    -1,    -1,    -1,    58,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    38,    39,    40,    41,    42,
-    43,    44,    45,    46,    47,    48,    49,    50,    51,    -1,
-    -1,    33,    -1,    -1,    -1,    58,    38,    39,    40,    41,
+    12,    12,    12,    12,    54,    12,    12,    63,    39,    40,
+    37,    38,    65,    12,    22,    52,     8,    37,    38,    51,
+    65,    53,    65,    55,    52,    57,    37,    38,    30,    66,
+    37,    65,    37,    38,    37,    38,    40,    68,    66,    66,
+    52,    43,    52,    52,    46,    52,    66,    49,    50,    51,
+    52,     1,    54,    52,    56,    66,    58,    59,    60,    66,
+    66,    66,    22,    66,    68,    12,    55,    56,    65,    71,
+    65,    65,    12,    75,    76,    77,    78,    79,    80,    81,
+    82,    83,    84,    85,    86,    87,    88,    89,   120,    52,
+    37,    38,    65,    95,    52,    65,    46,    37,    38,    12,
+    36,    52,    52,    66,    40,    36,   156,   157,    66,    59,
+    60,    65,    63,    64,    22,   117,    65,   149,    52,   121,
+    52,    71,    58,    59,    37,    38,   158,    58,    59,    52,
+    52,    52,    66,     3,    66,    85,    52,    65,    53,    54,
+    55,    56,    52,    66,    66,    66,    12,   149,   150,   151,
+    66,   153,   154,    52,   156,   157,    66,   159,   160,    65,
+     3,   163,   164,   165,   166,   167,    55,    66,     7,    52,
+    68,   173,   174,   223,    12,   225,    42,    43,    44,    45,
+    46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+    56,    51,    52,    53,    54,    55,    56,     3,    40,   231,
+   150,   151,    22,   153,   154,    41,     3,   257,   210,   159,
+   160,   213,     3,     7,   164,   165,   166,   167,    36,    38,
+    66,   223,    14,   225,     7,    66,    66,     0,    -1,    66,
+    -1,    -1,    -1,    -1,   236,   237,   238,   239,    -1,    -1,
+    -1,     0,     1,    -1,     3,     4,     5,    -1,     7,    -1,
+     9,    10,    11,    -1,    13,   257,    15,    16,    -1,    -1,
+    -1,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+    29,    30,    31,    32,    33,    34,    35,    -1,    37,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,   236,   237,   238,   239,
+    -1,    -1,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
+    59,    -1,    -1,    -1,    63,    64,    65,     3,     4,     5,
+     6,     7,    -1,     9,    10,    11,    -1,    13,    -1,    15,
+    16,    -1,    -1,    -1,    20,    21,    22,    23,    24,    25,
+    26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
     42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,    60,    38,
-    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
-    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    38,
-    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
-    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    38,
-    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
-    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    37,
-    38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
-    48,    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,
-    58,    38,    39,    40,    41,    42,    43,    44,    45,    46,
-    47,    48,    49,    50,    51,    -1,    -1,    -1,    -1,    -1,
-    -1,    58,    38,    39,    40,    41,    42,    43,    44,    45,
-    46,    47,    48,    49,    50,    51,    -1,    -1,    -1,    -1,
-    -1,    -1,    58
+    52,    53,    54,    55,    56,    51,    -1,    -1,    -1,    -1,
+    -1,    -1,    58,    59,    -1,    67,    -1,    -1,    -1,    65,
+    66,     3,     4,     5,     6,     7,    -1,     9,    10,    11,
+    -1,    13,    -1,    15,    16,    -1,    -1,    -1,    20,    21,
+    22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+    32,    33,    34,    35,    42,    43,    44,    45,    46,    47,
+    48,    49,    50,    51,    52,    53,    54,    55,    56,    51,
+    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,     3,     4,
+     5,    12,     7,    65,     9,    10,    11,    -1,    13,    -1,
+    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,    24,
+    25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+    35,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+    51,    52,    53,    54,    55,    56,    51,    -1,    -1,    -1,
+    -1,    -1,    -1,    58,    59,     3,     4,     5,    12,     7,
+    65,     9,    10,    11,    -1,    13,    -1,    15,    16,    -1,
+    -1,    -1,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    29,    30,    31,    32,    33,    34,    35,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+    54,    55,    56,    51,    -1,    -1,    -1,    -1,    -1,    -1,
+    58,    59,     3,     4,     5,    12,     7,    65,     9,    10,
+    11,    -1,    13,    -1,    15,    16,    -1,    -1,    -1,    20,
+    21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+    -1,    32,    33,    34,    35,    42,    43,    44,    45,    46,
+    47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,     3,
+     4,     5,    12,     7,    65,     9,    10,    11,    -1,    13,
+    -1,    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,
+    24,    25,    26,    27,    28,    29,    30,    -1,    32,    33,
+    34,    35,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    59,     3,     4,     5,    12,
+     7,    65,     9,    10,    11,    -1,    13,    -1,    15,    16,
+    -1,    -1,    -1,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,    29,    30,    -1,    32,    33,    34,    35,    42,
+    43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+    53,    54,    55,    56,    51,    -1,    -1,    -1,    -1,     3,
+     4,    58,    59,     7,    -1,     9,    10,    11,    65,    13,
+    -1,    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,
+    24,    25,    26,    27,    28,    29,    30,    -1,    32,    33,
+    34,    35,    12,    45,    46,    47,    48,    49,    50,    51,
+    52,    53,    54,    55,    56,    -1,    -1,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    59,    -1,    37,    12,    -1,
+    -1,    65,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    37,    12,    -1,    66,    -1,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+    54,    55,    56,    12,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    66,    -1,    42,    43,    44,    45,    46,    47,
+    48,    49,    50,    51,    52,    53,    54,    55,    56,    -1,
+    -1,    -1,    -1,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    52,    53,    54,    55,    56,    37,    -1,
+    -1,    -1,    -1,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    52,    53,    54,    55,    56,    -1,    -1,
+    -1,    -1,    -1,    -1,    63,    64,    42,    43,    44,    45,
+    46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    67,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    66,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    52,    53,    54,    55,    56,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+    54,    55,    56
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
 
@@ -934,7 +1018,7 @@ yynewstate:
 #endif
 
       /* Get the current used size of the three stacks, in elements.  */
-      int size = yyssp - yyss + 1;
+      int size = (int)(yyssp - yyss) + 1;
 
 #ifdef yyoverflow
       /* Each stack pointer address is followed by the size of
@@ -1271,7 +1355,7 @@ case 47:
 {yyvsp[0].tptr->GetValue(&yyval);;
     break;}
 case 48:
-{eval(&yyvsp[0], &yyval, 0L);;
+{eval(&yyvsp[0], &yyval);;
     break;}
 case 49:
 {yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
@@ -1295,10 +1379,10 @@ case 54:
 		yyval.val = ((yyvsp[-7].tptr->fnctptr)(&yyval)); yyval.type = NUM;;
     break;}
 case 55:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;;
+{yyval.type = NUM; yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L));;
     break;}
 case 56:
-{yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;;
+{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L));;
     break;}
 case 57:
 {yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
@@ -1349,85 +1433,127 @@ case 72:
 {(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
     break;}
 case 73:
-{yyval.val = yyvsp[-2].val != 0 ? eval(&yyvsp[0], &yyval, 0L) : 0.0;;
+{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
     break;}
 case 74:
-{yyval.val = yyvsp[-4].val != 0.0 ? eval(&yyvsp[-2], &yyval, 0L) : eval(&yyvsp[0], &yyval, 0L);;
+{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
     break;}
 case 75:
+{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 76:
+{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 77:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 78:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 79:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 80:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 81:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 82:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 83:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 84:
+{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 85:
+{if(yyvsp[-2].val != 0.0)eval(&yyval, &yyvsp[0]);;
+    break;}
+case 86:
+{yyvsp[-4].val != 0.0 ? eval(&yyval, &yyvsp[-2]) : eval(&yyval, &yyvsp[0]);;
+    break;}
+case 87:
+{for(int i=0; i< yy_maxiter; i++){
+					eval(&yyval, &yyvsp[-1]); 
+					if(yyval.val != 0.0)eval(&yyval, &yyvsp[0]);
+					else break;};
+    break;}
+case 88:
 {yyval.val = yyvsp[-2].val + yyvsp[0].val; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
 				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
     break;}
-case 76:
+case 89:
 {yyval.val = yyvsp[-2].val - yyvsp[0].val; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
 				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
     break;}
-case 77:
+case 90:
 {yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 78:
+case 91:
 {yyval.type = NUM; if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
 					else yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); ;
     break;}
-case 79:
-{yyval.val = -yyvsp[0].val;;
-    break;}
-case 80:
+case 92:
 {yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
     break;}
-case 81:
+case 93:
 {yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
     break;}
-case 82:
+case 94:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
     break;}
-case 83:
+case 95:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
     break;}
-case 84:
-{yyval.val = pow(yyvsp[-2].val, yyvsp[0].val);;
+case 96:
+{yyval.val = (yyvsp[0].val >0 && yyvsp[0].val/2.0 == floor(yyvsp[0].val/2.0)) ? fabs(pow(yyvsp[-2].val,yyvsp[0].val) ): pow(yyvsp[-2].val, yyvsp[0].val); yyval.type = NUM;;
     break;}
-case 85:
+case 97:
+{yyval.val = -yyvsp[0].val; yyval.type = NUM;;
+    break;}
+case 98:
 {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
     break;}
-case 86:
+case 99:
 {yyval.a_data = PushArray((double*)calloc((int)yyvsp[-1].val, sizeof(double))); yyval.a_count=(int)(yyvsp[-1].val); 
 					yyval.type = ARR; yyvsp[-3].tptr->SetValue(&yyval,&yyval);;
     break;}
-case 87:
+case 100:
 {if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) yyval.val = yyvsp[-3].a_data[(int)yyvsp[-1].val];
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 88:
+case 101:
 {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] = yyvsp[0].val;
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 89:
+case 102:
 {make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
     break;}
-case 90:
+case 103:
 {make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
     break;}
-case 91:
+case 104:
 {make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
     break;}
-case 92:
+case 105:
 {make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
     break;}
-case 93:
+case 106:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 94:
+case 107:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 95:
+case 108:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 96:
+case 109:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
 }
@@ -1659,7 +1785,7 @@ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt)
 {
 	h_name = h_n;	h2_name = h2_n;		type = typ;
 	next = nxt;	row = col = -1;		name = text = 0L;
-	var = 0.0;	isSSval = false;
+	var = 0.0;	isSSval = isValid = false;
 	a_data = 0L;	a_count = 0;
 	fnctptr = (double (*)(...))nop;
 }
@@ -1684,6 +1810,7 @@ symrec::GetValue()
 		isSSval = false;
 		row = col = -1;
 		}
+	if(!isValid) NoInit();
 	return var;
 }
 
@@ -1698,6 +1825,7 @@ symrec::GetValue(void *re)
 		res->a_data = 0L;	res->a_count = 0;
 		//GetResult( , , ,true) inhibits reentrance into parser !
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
+			isValid = true;
 			if(text) free(text);		text = 0L;
 			switch(ares.type) {
 			case ET_VALUE:
@@ -1729,6 +1857,7 @@ symrec::GetValue(void *re)
 		isSSval = false;
 		row = col = -1;
 		}
+	if(!isValid) NoInit();
 	if(a_data && a_count) {
 		res->a_data = a_data;	res->a_count = a_count;
 		res->val = 0.0;		res->type = ARR;
@@ -1755,6 +1884,7 @@ symrec::SetValue(double v)
 		isSSval = false;
 		row = col = -1;
 		}
+	isValid = true;
 	a_data = 0L;	a_count = 0;
 	return var = v;
 }
@@ -1774,9 +1904,11 @@ symrec::SetValue(void* d, void* s)
 		else curr_data->SetValue(row, col, src->val);
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
 		}
+	isValid = true;
 	var = src->val;
 	if(text) free(text);		text = 0L;
-	if(src->text && src->text[0]) 	text = strdup(src->text);
+	if(src->text && src->text[0])
+	text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0);
 	a_data = src->a_data;		a_count = src->a_count;
 	GetValue(d);
 	return;
@@ -1786,7 +1918,8 @@ void
 symrec::SetName(char *nam)
 {
 	if(name || !nam || !nam[0]) return;
-	name = strdup(nam);
+	name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
+	isValid = false;
 	if((name && curr_data) && (isalpha(name[0]) || name[0] == '$') && isdigit(name[strlen(name)-1])) isSSval=true;
 }
 
@@ -1801,6 +1934,19 @@ symrec::InitSS()
 		}
 }
 
+void
+symrec::NoInit()
+{
+	char message[200];
+
+#ifdef USE_WIN_SECURE
+	sprintf_s(message, 80, "Accessing variable '%s'\nwithout initialization!\n", name);
+#else
+	sprintf(message, "Accessing variable '%s'\nwithout initialization!\n", name);
+#endif
+	yywarn(message, true);
+}
+
 static void yyerror(char *s)
 {  
 	//called by yyparse on error
@@ -1815,6 +1961,17 @@ static void yyargserr(char *s)
 	last_err_desc = "#ARGS";
 }
 
+static char txt_tokenerr[80];
+static void yytokenerr(int c)
+{
+#ifdef USE_WIN_SECURE
+	sprintf_s(txt_tokenerr, 80, "Illegal character\nor token '%c'\n", (char)c);
+#else
+	sprintf(txt_tokenerr, "Illegal character\nor token '%c'\n", (char)c);
+#endif
+	yyerror(txt_tokenerr);
+}
+
 static void make_time(YYSTYPE *dst, double h, double m, double s)
 {
 	if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) {
@@ -1824,6 +1981,23 @@ static void make_time(YYSTYPE *dst, double h, double m, double s)
 	dst->val /= 24.0;		dst->type = TIME1;
 }
 
+static char yywarn_text[200];
+char  *yywarn(char *txt, bool bNew)
+{
+	if(bNew) {
+		if(txt && txt[0]) {
+			rlp_strcpy(yywarn_text, 200, txt);
+			return yywarn_text;
+			}
+		else {
+			yywarn_text[0] = 0;
+			return 0L;
+			}
+		}
+	else if(yywarn_text[0]) return yywarn_text;
+	else return 0L;
+}
+
 static void store_res(YYSTYPE *res)
 {
 	if(last_err_desc) {
@@ -1883,10 +2057,15 @@ static void store_res(YYSTYPE *res)
 static char *add_strings(char *st1, char *st2)
 {
 	char *newstr, *ret;
+	int cb;
 
 	if(st1 && st2) {
-		if(newstr = (char*)malloc(strlen(st1) +strlen(st2) +4)) {
+		if(newstr = (char*)malloc(cb = (int)(strlen(st1) +strlen(st2) +4))) {
+#ifdef USE_WIN_SECURE
+			sprintf_s(newstr, cb, "%s%s", st1, st2);
+#else
 			sprintf(newstr, "%s%s", st1, st2);
+#endif
 			ret = PushString(newstr);
 			free(newstr);
 			return ret;
@@ -1936,16 +2115,34 @@ static void pop_syntax()
 		}
 }
 
-static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum) 
+static void eval(YYSTYPE *dst, YYSTYPE *sr) 
 {
+	char *s_buffer;
+	int s_buff_pos, s_yychar, s_yynerrs, length;
 	anyResult *ar;
 
-	if(dum) yyerror("parse error");
-	if(!sr || !sr->text) return 0.0;
+	if(!sr || !sr->text) return;
 	parse_level++;
-	ar = do_formula(0L, sr->text);
+	s_buffer = buffer;		s_buff_pos = buff_pos;
+	s_yychar = yychar;	s_yynerrs = yynerrs;
+	if (sr->text && (length=(int)strlen(sr->text)) && (buffer = (char*)malloc(length+2))) {
+		strcpy(buffer, sr->text);		buffer[length++] = ';';
+		buffer[length] = 0;		buff_pos = 0;
+		do {
+			yyparse();
+			}while(buff_pos < length);
+		free(buffer);		ar = &line_res;
+		buffer = s_buffer;		buff_pos = s_buff_pos;
+		yychar = s_yychar;	yynerrs = s_yynerrs;
+		}
+	else return;
 	yylval.a_data = 0L;	yylval.a_count = 0;
 	switch(ar->type) {
+	case ET_BOOL:
+		dst->type = BOOLVAL;
+		dst->val = ar->value;
+		dst->text = 0L;
+		break;
 	case ET_VALUE:
 		dst->type = NUM;
 		dst->val = ar->value;
@@ -1963,7 +2160,6 @@ static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum)
 		break;
 		}
 	parse_level--;
-	return dst->val;
 }
 
 // more functions
@@ -2155,7 +2351,7 @@ static double sterr(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt(sr->a_count);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt((double)sr->a_count);
 		}
 	return sr->val;
 }
@@ -2259,7 +2455,7 @@ static double norminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
+		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
 	return sr->val;
@@ -2336,7 +2532,7 @@ static double lognorminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(lognorm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
+		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
 	return sr->val;
@@ -2353,6 +2549,17 @@ static double chidist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double chifreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = chi_freq(sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  chifreq(x, df).");
+	return sr->val;
+}
+
 static double chiinv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -2375,12 +2582,26 @@ static double tdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double tfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = t_freq(sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  tfreq(x, df).");
+	return sr->val;
+}
+
 static double tinv(YYSTYPE *sr)
 {
+	double dtmp;
+
 	if(!sr) return 0.0;
 	sr->val = 0.0;
+	dtmp = sr->a_data[1] > 1.0E+10 ? 1.0E+10 : sr->a_data[1];
         if(sr->a_data && sr->a_count == 2) {
-		sr->val = distinv(t_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
+		sr->val = fabs(distinv(t_dist,dtmp, 1.0, sr->a_data[0], 2.0));
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tinv(p, df).");
 	return sr->val;
@@ -2411,7 +2632,7 @@ static double poisfreq(YYSTYPE *sr)
 static double fdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	sr->val = 0;
+	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
@@ -2419,6 +2640,17 @@ static double fdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double ffreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = f_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  ffreq(x, df1, df2).");
+	return sr->val;
+}
+
 static double finv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -2491,7 +2723,7 @@ static double ttest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
-		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
 	return sr1->val;
@@ -2513,7 +2745,7 @@ static double utest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
-		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
 	return sr1->val;
@@ -2743,6 +2975,94 @@ static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest)
 	return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text);
 }
 
+static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	dst->type = NUM;
+	dst->val = (double)strpos(src1->text, src2->text);
+}
+
+static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	dst->type = STR;
+	dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+}
+
+static void _substr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	dst->type = STR;
+	dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val)));
+}
+
+static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum)
+{
+	if(dum) yyerror("parse error");
+	if(!sr || !sr->text) return 0.0;
+	return (double)((unsigned char)(sr->text[0]));
+}
+
+static void chr(YYSTYPE *dst, YYSTYPE *src)
+{
+	char tpl[] = "?\0";
+
+	if(!dst || !src) return;
+	tpl[0] = (src->val >=32.0 && src->val <= 255.0) ? (char)(src->val) :  '?';
+	dst->type = STR;
+	dst->text = PushString(tpl);
+}
+
+static void to_upper(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		for(i = 0; src->text[i]; i++) dst->text[i] = toupper(src->text[i]);
+		}
+	else dst->text = 0L;
+}
+
+static void to_lower(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		for(i = 0; src->text[i]; i++) dst->text[i] = tolower(src->text[i]);
+		}
+	else dst->text = 0L;
+}
+
+static void uc_first(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		dst->text[0] = toupper(src->text[0]);
+		}
+	else dst->text = 0L;
+}
+
+static void uc_word(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		dst->text[0] = toupper(src->text[0]);
+		for(i = 1; src->text[i]; i++) {
+			if(isalpha(src->text[i]) && src->text[i-1] < 'A') dst->text[i] = toupper(src->text[i]);
+			}
+		}
+	else dst->text = 0L;
+}
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -2833,7 +3153,11 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
-	INIT_SYM(FUNC4, "classes", classes),
+	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
+	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
+	INIT_SYM(SFNCT, "asc", asc),			INIT_SYM(YYFNC, "chr", chr),
+	INIT_SYM(YYFNC3, "strrepl",strrepl),		INIT_SYM(YYFNC3, "substr", _substr),
+	INIT_SYM(YYFNC2, "strpos",_strpos),		INIT_SYM(FUNC4, "classes", classes),
 	INIT_SYM(AFNCT, "rank", rank),			INIT_SYM(YYFNC, "ltrim", ltrim),
 	INIT_SYM(YYFNC, "rtrim", rtrim),		INIT_SYM(YYFNC, "trim", trim),
 	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(YYFNC, "crank", _crank),
@@ -2844,7 +3168,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FNCT, "dow", dow),			INIT_SYM(FNCT, "doy", doy),
 	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
 	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
-	INIT_SYM(FNCT, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
+	INIT_SYM(YYFNC, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
 	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(FUNC2, "pearson", pearson),
 	INIT_SYM(FUNC2, "spearman", spearman),		INIT_SYM(FUNC2, "kendall", kendall),		
 	INIT_SYM(FUNC2, "correl", pearson),		INIT_SYM(FUNC2, "regression", regression),
@@ -2859,10 +3183,14 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "median", quartile2),		INIT_SYM(AFNCT, "quartile1", quartile1),
 	INIT_SYM(AFNCT, "quartile2",quartile2),		INIT_SYM(AFNCT, "quartile3", quartile3),
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
-	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tinv", tinv),
+	INIT_SYM(AFNCT, "tdist", tdist),		
+	INIT_SYM(AFNCT, "tfreq", tfreq),
+	INIT_SYM(AFNCT, "tinv", tinv),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
 	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
-	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "expinv", expinv),		
+	INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),
 	INIT_SYM(AFNCT, "finv", finv),			INIT_SYM(AFNCT, "gammp", _gammp),
 	INIT_SYM(AFNCT, "gammq", _gammq),		INIT_SYM(AFNCT, "beta", beta),
 	INIT_SYM(AFNCT, "betai", _betai),		INIT_SYM(AFNCT, "bincof", _bincof),
@@ -2872,8 +3200,9 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
 	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
+	INIT_SYM(AFNCT, "chifreq", chifreq),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
-	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
+	INIT_SYM(YYFNC, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
 	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
 	INIT_SYM(FNCT, "gammaln", gammln),		INIT_SYM(FNCT, "factorial", factorial),
 	INIT_SYM(YYFNC, "rand", rand1),			INIT_SYM(FNCT, "srand", srand),
@@ -3188,6 +3517,9 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 	case 362:
 		if(h2_nam == 42878) return IF;
 		break;
+	case 28421:
+		if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE);
+		break;
 	case 1457:
 		if(h2_nam == 18357885) return DIM;
 		break;
@@ -3204,24 +3536,66 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 	return 0;
 }
 
+static char *copy_block()
+{
+	char first[50], last[50], *res, *src;
+	int i, j, level, mode;
+
+	src = buffer + buff_pos-1;
+	switch(*src){
+	case '{':
+		first[0] = '{';		last[0] = '}';	break;
+	case '(':
+		first[0] = '(';		last[0] = ')';	break;
+		}
+	if(!(res = (char*)malloc(strlen(src)+2))) return 0L;
+	for(i = 1, level = mode = j = 0; src[i]; i++) {
+		res[j++] = src[i];
+		if(mode && level) {					//embeded string
+			if(src[i] == last[level]) {
+				mode = 0;	level--;
+				}
+			res[j++] = src[i];
+			}
+		else {
+ 			if(src[i] == last[level]) {
+				if(level) level--;
+				else {
+					res[j-1] = 0;	buff_pos += j;
+					return res;
+					}
+				}
+			else switch(src[i]) {
+			case '"':
+				level++;	first[level] = last[level] = '"';			break;
+			case '\'':
+				level++;	first[level] = last[level] = '\'';			break;
+			case '{':
+				level++;	first[level] = '{';		last[level] = '}';	break;
+			case '(':
+				level++;	first[level] = '(';		last[level] = ')';	break;
+				}
+			}
+		}
+	return res;
+}
+
 static symrec *curr_sym;
 static int yylex (void)
 {
 	int i, c, tok;
 	unsigned int h_nam, h2_nam;
-	char tmp_txt[80];
+	char tmp_txt[80], *block;
 	symrec *s;
 
 	while((c = buffer[buff_pos++]) == ' ' || c == '\t');	//get first nonwhite char
 	if(!c) return 0;
 	//test for block statement
 	if(c == '{') {
-		for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != '}')); buff_pos++) {
-			tmp_txt[i++] = (char)tok;
+		if(block = copy_block()) {
+			yylval.text = PushString(block);
+			free(block);
 			}
-		if(buffer[buff_pos] == '}')buff_pos++;
-		tmp_txt[i] = 0;
-		yylval.text = PushString(tmp_txt);
 		return yylval.type = BLOCK;
 		}
 	//test for '..' operator
@@ -3230,7 +3604,7 @@ static int yylex (void)
 		return yylval.type = SER;
 		}
 	//test for number
-	if(c == '.' || isdigit(c)) {
+	if(c > 31 &&(c == '.' || isdigit(c))) {
 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) {
 			tmp_txt[i++] = (char)c;
 			if(i && buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){
@@ -3247,8 +3621,8 @@ static int yylex (void)
 		return yylval.type = NUM;
 		}
 	//test for name or stringtoken
-	if(isalpha(c) || c=='$') {
- 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && (isalnum(c) || c == '$')); buff_pos++) {
+	if(c > 31 && (isalpha(c) || c=='$')) {
+ 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
 			tmp_txt[i++] = (char)c; 
 			}
 		tmp_txt[i] = 0;
@@ -3309,6 +3683,13 @@ static int yylex (void)
 		pop_syntax();
 		break;
 	case '(':
+		if(syntax_level->last_tok == WHILE){
+			if(block = copy_block()) {
+				yylval.text = PushString(block);
+				free(block);
+				}
+			return yylval.type = PBLOCK;
+			}
 		push_syntax();
 	case '?':
 		if(syntax_level) syntax_level->last_tok = c;
@@ -3335,6 +3716,7 @@ static int yylex (void)
 		buff_pos++;		return tok;
 		}
 	//Any other character is a token by itself
+	if(c < 0 || c > 127)yytokenerr(c);
 	return c;
 }
 
@@ -3361,7 +3743,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	push_parser();
 	init_table();
 	if(param) {
-		length = strlen(param);
+		length = (int)strlen(param);
 		if(!(buffer = (char*)malloc(length+2))){
 			pop_parser();
 			return false;
@@ -3373,7 +3755,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			}while(buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
-	length = strlen(expr);
+	length = (int)strlen(expr);
 	buffer = expr;		sx = putsym(hn_x, h2_x, VAR);
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
@@ -3420,7 +3802,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	push_parser();
 	init_table();
 	if(param) {
-		length = strlen(param);
+		length = (int)strlen(param);
 		if(!(buffer = (char*)malloc(length+2))){
 			pop_parser();
 			return false;
@@ -3432,7 +3814,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			}while(buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
-	length = strlen(expr);		buffer = expr;
+	length = (int)strlen(expr);		buffer = expr;
 	sx = putsym(hn_x, h2_x, VAR);	sz = putsym(hn_z, h2_z, VAR);
 	nr = iround((z2-z1)/zstep)+1;	nc = iround((x2-x1)/xstep)+1;
 	d->Init(nr, nc);
@@ -3476,7 +3858,7 @@ anyResult *do_formula(DataObj *d, char *expr)
 		return &ret;
 		}
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(expr);
+	init_table();		length = (int)strlen(expr);
 	if(!(buffer = (char*)malloc(length+2))){
 		pop_parser();
 		return &ret;
@@ -3502,20 +3884,21 @@ anyResult *do_formula(DataObj *d, char *expr)
 
 bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 {
-	int length, tok, pos, i;
+	int length, length2, tok, pos, i;
 	char *res, desc1[2], desc2[2];
 
 	if(d) curr_data = d;
 	if(!curr_data || !of || !nf) return false;
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(of);
+	init_table();		length = (int)strlen(of);
 	if(!(buffer = (char*)malloc(length+2))){
 		pop_parser();
 		return false;
 		}
 	strcpy(buffer, of);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = pos = 0;
-	res = (char *)calloc(length*2+10, sizeof(char));
+	if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false;
+	length2--;
 	do {
 		tok = yylex ();
 		if(tok && tok < 256) {
@@ -3524,97 +3907,121 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			}
 		else switch(tok) {
 			case NUM:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, 20, "%g", yylval.val);
+#else
 				pos += sprintf(res+pos, "%g", yylval.val);
+#endif
 				break;
 			case FNCT:	case FUNC1:	case FUNC2:	case FUNC3:	case AFNCT:
 			case SFNCT:	case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:
-				pos += sprintf(res+pos, "%s", curr_sym->name);
+			case YYFNC2:	case YYFNC3:
+				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case COLR:			case COLC:
-				pos += sprintf(res+pos, ":");
+				res[pos++] = ':';
 				break;
 			case PSEP:
-				pos += sprintf(res+pos, ";");
+				res[pos++] = ';';
 				break;
 			case CLVAL:
-				pos += sprintf(res+pos, "$$");
+				res[pos++] = '$';	res[pos++] = '$';
 				break;
 			case CLAUSE:
-				pos += sprintf(res+pos, " where ");
+				pos += rlp_strcpy(res+pos, length2-pos, " where ");
 				break;
 			case VAR:
 				curr_sym->InitSS();
 				if(curr_sym->col >= 0 && curr_sym->row >= 0) {
 					desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0;
-					for(i=strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
+					for(i=(int)strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
 					if(curr_sym->name[0] == '$') desc1[0] = '$';
 					if(curr_sym->name[i] == '$') desc2[0] = '$';
+#ifdef USE_WIN_SECURE
+					pos += sprintf_s(res+pos, length2-pos, "%s%s%s%d", desc1,
+#else
 					pos += sprintf(res+pos, "%s%s%s%d", desc1, 
+#endif
 						Int2ColLabel(desc1[0] || curr_sym->col < c0 ? curr_sym->col : curr_sym->col+dx >=0 ?
 						curr_sym->col+dx > c0 ? curr_sym->col+dx : c0 : 0, false),
 						desc2, desc2[0] || curr_sym->row < r0 ? curr_sym->row+1 : curr_sym->row + dy >= 0 ? 
 						curr_sym->row+dy > r0 ? curr_sym->row+1+dy : r0 : 1);
 					}
-				else pos += sprintf(res+pos, "%s ", curr_sym->name);
+				else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case STR:
 				pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
 				break;
 			case SER:
-				pos += sprintf(res+pos, "..");
+				res[pos++] = '.';	res[pos++] = '.';
 				break;
 			case INC:
-				pos += sprintf(res+pos, "++");
+				res[pos++] = '+';	res[pos++] = '+';
 				break;
 			case DEC:
-				pos += sprintf(res+pos, "--");
+				res[pos++] = '-';	res[pos++] = '-';
 				break;
 			case PI:
-				pos += sprintf(res+pos, "pi");
+				res[pos++] = 'p';	res[pos++] = 'i';
 				break;
 			case E:
-				pos += sprintf(res+pos, "e");
+				res[pos++] = 'e';
 				break;
 			case BTRUE:
-				pos += sprintf(res+pos, "true");
+				pos += rlp_strcpy(res+pos, length2-pos, "true");
 				break;
 			case BFALSE:
-				pos += sprintf(res+pos, "false");
+				pos += rlp_strcpy(res+pos, length2-pos, "false");
 				break;
 			case AND:
-				pos += sprintf(res+pos, " && ");
+				pos += rlp_strcpy(res+pos, length2-pos, " && ");
 				break;
 			case OR:
-				pos += sprintf(res+pos, " || ");
+				pos += rlp_strcpy(res+pos, length2-pos, " || ");
 				break;
 			case EQ:
-				pos += sprintf(res+pos, " == ");
+				pos += rlp_strcpy(res+pos, length2-pos, " == ");
 				break;
 			case NE:
-				pos += sprintf(res+pos, " != ");
+				pos += rlp_strcpy(res+pos, length2-pos, " != ");
 				break;
 			case GT:
-				pos += sprintf(res+pos, ">");
+				res[pos++] = '>';
 				break;
 			case GE:
-				pos += sprintf(res+pos, ">=");
+				res[pos++] = '>';	res[pos++] = '=';
 				break;
 			case LT:
-				pos += sprintf(res+pos, "<");
+				res[pos++] = '<';
 				break;
 			case LE:
-				pos += sprintf(res+pos, "<=");
+				res[pos++] = '<';	res[pos++] = '=';
 				break;
 			case IF: 
-				pos += sprintf(res+pos, "if");
+				res[pos++] = 'i';	res[pos++] = 'f';
+				break;
+			case WHILE: 
+				pos += rlp_strcpy(res+pos, length2-pos, "while");
 				break;
 			case ELSE: 
-				pos += sprintf(res+pos, "else");
+				pos += rlp_strcpy(res+pos, length2-pos, "else");
 				break;
 			case BLOCK:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
+#else
 				pos += sprintf(res+pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
+#endif
+				break;
+			case PBLOCK:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
+#else
+				pos += sprintf(res+pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
+#endif
 				break;
 			}
+		res[pos] = 0;
 		}while(buff_pos < length);
 	while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} 
 	strcpy(nf, res);	free(res);
@@ -3641,7 +4048,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 	//calc result
 	symx->SetValue(x);	symz->SetValue(z);	
 	buffer = txt_formula;
-	buff_pos = 0;		length = strlen(txt_formula);
+	buff_pos = 0;		length = (int)strlen(txt_formula);
 	do {	yyparse();	}while(buff_pos < length);
 	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
@@ -3726,7 +4133,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		}
 	//common initialization for parser tasks
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(*par);
+	init_table();		length = (int)strlen(*par);
 	//process parameters
 	if(!(buffer = (char*)malloc(length+2))){
 		clear_table();	pop_parser();
@@ -3775,10 +4182,11 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
 		j += l;			k += l;
 		}
-	free(*par);	*par = strdup(tmp_txt);
+	free(*par);
+	*par = (char*)memdup(tmp_txt, (int)strlen(tmp_txt)+1, 0);
 	if(chi_2) *chi_2 = chisq;
 	//write back spreadsheet data if necessary
-	buffer = *par;	length = strlen(buffer);
+	buffer = *par;	length = (int)strlen(buffer);
 	do {
 		yyparse();
 		}while(buff_pos < length);
@@ -3797,11 +4205,3 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
-
-
-
-
-
-
-
-
diff --git a/mfcalc.y b/mfcalc.y
index 3069b87..e033364 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -43,9 +43,10 @@ public:
         void SetValue(void* dest, void* src);
 	void SetName(char *nam);
 	void InitSS();
+	void NoInit();
 
 private:
-	bool isSSval;
+	bool isSSval, isValid;
 
 };
 
@@ -69,6 +70,8 @@ typedef struct{
 
 }YYSTYPE;
 
+static int yy_maxiter = 1000;
+
 static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
 static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
 static int push(YYSTYPE *res, YYSTYPE *val);
@@ -78,7 +81,7 @@ static double *PushArray(double *arr);
 static double *ReallocArray(double *arr, int size);
 static char *add_strings(char *st1, char *st2);
 static char *string_value(YYSTYPE *exp);
-static double eval(YYSTYPE *sr, YYSTYPE *dst, char* dum);
+static void eval(YYSTYPE *dst, YYSTYPE *sr);
 static int range_array(YYSTYPE * res, char *range);
 static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
@@ -101,9 +104,10 @@ static int parse_level = 0;		//count reentrances into parser
 #define MAX_PARSE 20			//maximum number of reentances 
 %}
 
-%token <val>  NUM BOOLVAL STR ARR BLOCK PI E CLVAL PSEP IF ELSE BTRUE BFALSE
-%token <val>  DATE1 TIME1 DATETIME1 DIM
-%token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 FUNC2 FUNC3 TXT SRFUNC YYFNC FUNC4
+%token <val>  NUM BOOLVAL STR ARR BLOCK PBLOCK PI E CLVAL PSEP IF ELSE 
+%token <val>  BTRUE BFALSE DATE1 TIME1 DATETIME1 DIM WHILE
+%token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 FUNC2 FUNC3 TXT SRFUNC YYFNC
+%token <tptr> FUNC4 YYFNC2 YYFNC3
 %type  <val>  exp str_exp arr bool
 
 %right  '='
@@ -117,11 +121,11 @@ static int parse_level = 0;		//count reentrances into parser
 %left   '-' '+'
 %left   '*' '/'
 %left	'['
-%left   NEG 		/* negation-unary minus */
+%left 	'^'	 	/* exponentiation       */
+%left 	NEG 		/* negation-unary minus */
 %left	INC DEC		/* increment, decrement */
 %left	PINC PDEC	/* pre- increment, decrement */
 %left	PDIM		/* dimension array */
-%right  '^'	 	/* exponentiation       */
 
 /* Grammar follows */
 %%
@@ -186,7 +190,7 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|PI				{$$ = _PI; yyval.type = NUM;}
 	|E				{$$ = 2.71828182845905; yyval.type = NUM;}
 	|VAR				{$1->GetValue(&yyval);}
-	|BLOCK			{eval(&yyvsp[0], &yyval, 0L);}
+	|BLOCK			{eval(&yyvsp[0], &yyval);}
 	|VAR '=' exp		{$1->SetValue(&yyval, &yyvsp[0]);}
 	|VAR '=' str_exp	{$1->SetValue(&yyval, &yyvsp[0]);}
 	|FNCT '(' exp ')'	{$$ = (($1->fnctptr)($3)); yyval.type = NUM;}
@@ -196,8 +200,8 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|AFNCT '(' exp PSEP exp PSEP exp ')' { yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
 		yyval.a_count = 3; yyval.a_data[0] = $3; yyval.a_data[1] = $5; yyval.a_data[2] = $7;	
 		$$ = (($1->fnctptr)(&yyval)); yyval.type = NUM;}
-	|SFNCT '(' str_exp ')'	{$$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;}
-	|SFNCT '(' exp ')'	{yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;}
+	|SFNCT '(' str_exp ')'	{yyval.type = NUM; $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L));}
+	|SFNCT '(' exp ')'	{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L));}
 	|SFNCT '(' str_exp PSEP str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
 	|SFNCT '(' exp PSEP str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
 	|SFNCT '(' exp PSEP exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
@@ -214,8 +218,24 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|FUNC1 '(' arr PSEP range ')' {$$ = ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text));  yyval.type = NUM;}
 	|YYFNC '(' ')'		{(*$1->fnctptr)(&yyval, 0L);}
 	|YYFNC '(' arr ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-1]);}
-	|IF '(' exp ')' BLOCK	{$$ = $3 != 0 ? eval(&yyvsp[0], &yyval, 0L) : 0.0;}
-	|IF '(' exp ')' BLOCK ELSE BLOCK	{$$ = $3 != 0.0 ? eval(&yyvsp[-2], &yyval, 0L) : eval(&yyvsp[0], &yyval, 0L);}
+	|YYFNC2 '(' exp PSEP exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC2 '(' str_exp PSEP exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC2 '(' exp PSEP str_exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC2 '(' str_exp PSEP str_exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' str_exp PSEP str_exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' exp PSEP str_exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' str_exp PSEP exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' str_exp PSEP str_exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' exp PSEP exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' exp PSEP str_exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' str_exp PSEP exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' exp PSEP exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|IF '(' exp ')' BLOCK	{if($3 != 0.0)eval(&yyval, &yyvsp[0]);}
+	|IF '(' exp ')' BLOCK ELSE BLOCK	{$3 != 0.0 ? eval(&yyval, &yyvsp[-2]) : eval(&yyval, &yyvsp[0]);}
+	|WHILE PBLOCK BLOCK	{for(int i=0; i< yy_maxiter; i++){
+					eval(&yyval, &yyvsp[-1]); 
+					if(yyval.val != 0.0)eval(&yyval, &yyvsp[0]);
+					else break;}}
 	|exp '+' exp		{$$ = $1 + $3; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
@@ -227,12 +247,12 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|exp '*' exp		{$$ = $1 * $3; yyval.type = NUM;}
 	|exp '/' exp		{yyval.type = NUM; if($3 != 0.0) $$ = $1 / $3;
 					else $$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); }
-	|'-' exp  %prec NEG	{$$ = -$2;}
 	|VAR INC		{$$=$1->GetValue(); $1->SetValue($$+1.0); $$ -= 1.0; yyval.type = NUM;}
 	|VAR DEC		{$$=$1->GetValue(); $1->SetValue($$-1.0); $$ += 1.0; yyval.type = NUM;}
 	|INC VAR %prec PINC	{$$=$2->GetValue(); $2->SetValue($$+1.0); yyval.type = NUM;}
 	|DEC VAR %prec PDEC	{$$=$2->GetValue(); $2->SetValue($$-1.0); yyval.type = NUM;}
-	|exp '^' exp		{$$ = pow($1, $3);}
+	|exp '^' exp		{$$ = ($3 >0 && $3/2.0 == floor($3/2.0)) ? fabs(pow($1,$3) ): pow($1, $3); yyval.type = NUM;}
+	|'-' exp  %prec NEG	{$$ = -$2; yyval.type = NUM;}
 	|'(' arr ')'		{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;}
 	|DIM VAR %prec PDIM '[' exp ']'	{yyval.a_data = PushArray((double*)calloc((int)$4, sizeof(double))); yyval.a_count=(int)($4); 
 					yyval.type = ARR; $2->SetValue(&yyval,&yyval);}
@@ -256,7 +276,7 @@ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt)
 {
 	h_name = h_n;	h2_name = h2_n;		type = typ;
 	next = nxt;	row = col = -1;		name = text = 0L;
-	var = 0.0;	isSSval = false;
+	var = 0.0;	isSSval = isValid = false;
 	a_data = 0L;	a_count = 0;
 	fnctptr = (double (*)(...))nop;
 }
@@ -281,6 +301,7 @@ symrec::GetValue()
 		isSSval = false;
 		row = col = -1;
 		}
+	if(!isValid) NoInit();
 	return var;
 }
 
@@ -295,6 +316,7 @@ symrec::GetValue(void *re)
 		res->a_data = 0L;	res->a_count = 0;
 		//GetResult( , , ,true) inhibits reentrance into parser !
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
+			isValid = true;
 			if(text) free(text);		text = 0L;
 			switch(ares.type) {
 			case ET_VALUE:
@@ -326,6 +348,7 @@ symrec::GetValue(void *re)
 		isSSval = false;
 		row = col = -1;
 		}
+	if(!isValid) NoInit();
 	if(a_data && a_count) {
 		res->a_data = a_data;	res->a_count = a_count;
 		res->val = 0.0;		res->type = ARR;
@@ -352,6 +375,7 @@ symrec::SetValue(double v)
 		isSSval = false;
 		row = col = -1;
 		}
+	isValid = true;
 	a_data = 0L;	a_count = 0;
 	return var = v;
 }
@@ -371,9 +395,11 @@ symrec::SetValue(void* d, void* s)
 		else curr_data->SetValue(row, col, src->val);
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
 		}
+	isValid = true;
 	var = src->val;
 	if(text) free(text);		text = 0L;
-	if(src->text && src->text[0]) 	text = strdup(src->text);
+	if(src->text && src->text[0])
+	text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0);
 	a_data = src->a_data;		a_count = src->a_count;
 	GetValue(d);
 	return;
@@ -383,7 +409,8 @@ void
 symrec::SetName(char *nam)
 {
 	if(name || !nam || !nam[0]) return;
-	name = strdup(nam);
+	name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
+	isValid = false;
 	if((name && curr_data) && (isalpha(name[0]) || name[0] == '$') && isdigit(name[strlen(name)-1])) isSSval=true;
 }
 
@@ -398,6 +425,19 @@ symrec::InitSS()
 		}
 }
 
+void
+symrec::NoInit()
+{
+	char message[200];
+
+#ifdef USE_WIN_SECURE
+	sprintf_s(message, 80, "Accessing variable '%s'\nwithout initialization!\n", name);
+#else
+	sprintf(message, "Accessing variable '%s'\nwithout initialization!\n", name);
+#endif
+	yywarn(message, true);
+}
+
 static void yyerror(char *s)
 {  
 	//called by yyparse on error
@@ -412,6 +452,17 @@ static void yyargserr(char *s)
 	last_err_desc = "#ARGS";
 }
 
+static char txt_tokenerr[80];
+static void yytokenerr(int c)
+{
+#ifdef USE_WIN_SECURE
+	sprintf_s(txt_tokenerr, 80, "Illegal character\nor token '%c'\n", (char)c);
+#else
+	sprintf(txt_tokenerr, "Illegal character\nor token '%c'\n", (char)c);
+#endif
+	yyerror(txt_tokenerr);
+}
+
 static void make_time(YYSTYPE *dst, double h, double m, double s)
 {
 	if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) {
@@ -421,6 +472,23 @@ static void make_time(YYSTYPE *dst, double h, double m, double s)
 	dst->val /= 24.0;		dst->type = TIME1;
 }
 
+static char yywarn_text[200];
+char  *yywarn(char *txt, bool bNew)
+{
+	if(bNew) {
+		if(txt && txt[0]) {
+			rlp_strcpy(yywarn_text, 200, txt);
+			return yywarn_text;
+			}
+		else {
+			yywarn_text[0] = 0;
+			return 0L;
+			}
+		}
+	else if(yywarn_text[0]) return yywarn_text;
+	else return 0L;
+}
+
 static void store_res(YYSTYPE *res)
 {
 	if(last_err_desc) {
@@ -480,10 +548,15 @@ static void store_res(YYSTYPE *res)
 static char *add_strings(char *st1, char *st2)
 {
 	char *newstr, *ret;
+	int cb;
 
 	if(st1 && st2) {
-		if(newstr = (char*)malloc(strlen(st1) +strlen(st2) +4)) {
+		if(newstr = (char*)malloc(cb = (int)(strlen(st1) +strlen(st2) +4))) {
+#ifdef USE_WIN_SECURE
+			sprintf_s(newstr, cb, "%s%s", st1, st2);
+#else
 			sprintf(newstr, "%s%s", st1, st2);
+#endif
 			ret = PushString(newstr);
 			free(newstr);
 			return ret;
@@ -533,16 +606,34 @@ static void pop_syntax()
 		}
 }
 
-static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum) 
+static void eval(YYSTYPE *dst, YYSTYPE *sr) 
 {
+	char *s_buffer;
+	int s_buff_pos, s_yychar, s_yynerrs, length;
 	anyResult *ar;
 
-	if(dum) yyerror("parse error");
-	if(!sr || !sr->text) return 0.0;
+	if(!sr || !sr->text) return;
 	parse_level++;
-	ar = do_formula(0L, sr->text);
+	s_buffer = buffer;		s_buff_pos = buff_pos;
+	s_yychar = yychar;	s_yynerrs = yynerrs;
+	if (sr->text && (length=(int)strlen(sr->text)) && (buffer = (char*)malloc(length+2))) {
+		strcpy(buffer, sr->text);		buffer[length++] = ';';
+		buffer[length] = 0;		buff_pos = 0;
+		do {
+			yyparse();
+			}while(buff_pos < length);
+		free(buffer);		ar = &line_res;
+		buffer = s_buffer;		buff_pos = s_buff_pos;
+		yychar = s_yychar;	yynerrs = s_yynerrs;
+		}
+	else return;
 	yylval.a_data = 0L;	yylval.a_count = 0;
 	switch(ar->type) {
+	case ET_BOOL:
+		dst->type = BOOLVAL;
+		dst->val = ar->value;
+		dst->text = 0L;
+		break;
 	case ET_VALUE:
 		dst->type = NUM;
 		dst->val = ar->value;
@@ -560,7 +651,6 @@ static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum)
 		break;
 		}
 	parse_level--;
-	return dst->val;
 }
 
 // more functions
@@ -752,7 +842,7 @@ static double sterr(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt(sr->a_count);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt((double)sr->a_count);
 		}
 	return sr->val;
 }
@@ -856,7 +946,7 @@ static double norminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
+		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
 	return sr->val;
@@ -933,7 +1023,7 @@ static double lognorminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(lognorm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
+		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
 	return sr->val;
@@ -950,6 +1040,17 @@ static double chidist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double chifreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = chi_freq(sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  chifreq(x, df).");
+	return sr->val;
+}
+
 static double chiinv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -972,12 +1073,26 @@ static double tdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double tfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = t_freq(sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  tfreq(x, df).");
+	return sr->val;
+}
+
 static double tinv(YYSTYPE *sr)
 {
+	double dtmp;
+
 	if(!sr) return 0.0;
 	sr->val = 0.0;
+	dtmp = sr->a_data[1] > 1.0E+10 ? 1.0E+10 : sr->a_data[1];
         if(sr->a_data && sr->a_count == 2) {
-		sr->val = distinv(t_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
+		sr->val = fabs(distinv(t_dist,dtmp, 1.0, sr->a_data[0], 2.0));
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tinv(p, df).");
 	return sr->val;
@@ -1008,7 +1123,7 @@ static double poisfreq(YYSTYPE *sr)
 static double fdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	sr->val = 0;
+	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
@@ -1016,6 +1131,17 @@ static double fdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double ffreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = f_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  ffreq(x, df1, df2).");
+	return sr->val;
+}
+
 static double finv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -1088,7 +1214,7 @@ static double ttest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
-		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
 	return sr1->val;
@@ -1110,7 +1236,7 @@ static double utest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){
-		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
 	return sr1->val;
@@ -1340,6 +1466,94 @@ static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest)
 	return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text);
 }
 
+static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	dst->type = NUM;
+	dst->val = (double)strpos(src1->text, src2->text);
+}
+
+static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	dst->type = STR;
+	dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+}
+
+static void _substr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	dst->type = STR;
+	dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val)));
+}
+
+static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum)
+{
+	if(dum) yyerror("parse error");
+	if(!sr || !sr->text) return 0.0;
+	return (double)((unsigned char)(sr->text[0]));
+}
+
+static void chr(YYSTYPE *dst, YYSTYPE *src)
+{
+	char tpl[] = "?\0";
+
+	if(!dst || !src) return;
+	tpl[0] = (src->val >=32.0 && src->val <= 255.0) ? (char)(src->val) :  '?';
+	dst->type = STR;
+	dst->text = PushString(tpl);
+}
+
+static void to_upper(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		for(i = 0; src->text[i]; i++) dst->text[i] = toupper(src->text[i]);
+		}
+	else dst->text = 0L;
+}
+
+static void to_lower(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		for(i = 0; src->text[i]; i++) dst->text[i] = tolower(src->text[i]);
+		}
+	else dst->text = 0L;
+}
+
+static void uc_first(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		dst->text[0] = toupper(src->text[0]);
+		}
+	else dst->text = 0L;
+}
+
+static void uc_word(YYSTYPE *dst, YYSTYPE *src)
+{
+	int i;
+
+	if(!dst || !src) return;
+	dst->type = STR;
+	if(src->text && src->text[0]) {
+		dst->text = PushString(src->text);
+		dst->text[0] = toupper(src->text[0]);
+		for(i = 1; src->text[i]; i++) {
+			if(isalpha(src->text[i]) && src->text[i-1] < 'A') dst->text[i] = toupper(src->text[i]);
+			}
+		}
+	else dst->text = 0L;
+}
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -1430,7 +1644,11 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
-	INIT_SYM(FUNC4, "classes", classes),
+	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
+	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
+	INIT_SYM(SFNCT, "asc", asc),			INIT_SYM(YYFNC, "chr", chr),
+	INIT_SYM(YYFNC3, "strrepl",strrepl),		INIT_SYM(YYFNC3, "substr", _substr),
+	INIT_SYM(YYFNC2, "strpos",_strpos),		INIT_SYM(FUNC4, "classes", classes),
 	INIT_SYM(AFNCT, "rank", rank),			INIT_SYM(YYFNC, "ltrim", ltrim),
 	INIT_SYM(YYFNC, "rtrim", rtrim),		INIT_SYM(YYFNC, "trim", trim),
 	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(YYFNC, "crank", _crank),
@@ -1441,7 +1659,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FNCT, "dow", dow),			INIT_SYM(FNCT, "doy", doy),
 	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
 	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
-	INIT_SYM(FNCT, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
+	INIT_SYM(YYFNC, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
 	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(FUNC2, "pearson", pearson),
 	INIT_SYM(FUNC2, "spearman", spearman),		INIT_SYM(FUNC2, "kendall", kendall),		
 	INIT_SYM(FUNC2, "correl", pearson),		INIT_SYM(FUNC2, "regression", regression),
@@ -1456,10 +1674,14 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "median", quartile2),		INIT_SYM(AFNCT, "quartile1", quartile1),
 	INIT_SYM(AFNCT, "quartile2",quartile2),		INIT_SYM(AFNCT, "quartile3", quartile3),
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
-	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tinv", tinv),
+	INIT_SYM(AFNCT, "tdist", tdist),		
+	INIT_SYM(AFNCT, "tfreq", tfreq),
+	INIT_SYM(AFNCT, "tinv", tinv),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
 	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
-	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "expinv", expinv),		
+	INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),
 	INIT_SYM(AFNCT, "finv", finv),			INIT_SYM(AFNCT, "gammp", _gammp),
 	INIT_SYM(AFNCT, "gammq", _gammq),		INIT_SYM(AFNCT, "beta", beta),
 	INIT_SYM(AFNCT, "betai", _betai),		INIT_SYM(AFNCT, "bincof", _bincof),
@@ -1469,8 +1691,9 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
 	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
+	INIT_SYM(AFNCT, "chifreq", chifreq),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
-	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
+	INIT_SYM(YYFNC, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
 	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
 	INIT_SYM(FNCT, "gammaln", gammln),		INIT_SYM(FNCT, "factorial", factorial),
 	INIT_SYM(YYFNC, "rand", rand1),			INIT_SYM(FNCT, "srand", srand),
@@ -1785,6 +2008,9 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 	case 362:
 		if(h2_nam == 42878) return IF;
 		break;
+	case 28421:
+		if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE);
+		break;
 	case 1457:
 		if(h2_nam == 18357885) return DIM;
 		break;
@@ -1801,24 +2027,66 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 	return 0;
 }
 
+static char *copy_block()
+{
+	char first[50], last[50], *res, *src;
+	int i, j, level, mode;
+
+	src = buffer + buff_pos-1;
+	switch(*src){
+	case '{':
+		first[0] = '{';		last[0] = '}';	break;
+	case '(':
+		first[0] = '(';		last[0] = ')';	break;
+		}
+	if(!(res = (char*)malloc(strlen(src)+2))) return 0L;
+	for(i = 1, level = mode = j = 0; src[i]; i++) {
+		res[j++] = src[i];
+		if(mode && level) {					//embeded string
+			if(src[i] == last[level]) {
+				mode = 0;	level--;
+				}
+			res[j++] = src[i];
+			}
+		else {
+ 			if(src[i] == last[level]) {
+				if(level) level--;
+				else {
+					res[j-1] = 0;	buff_pos += j;
+					return res;
+					}
+				}
+			else switch(src[i]) {
+			case '"':
+				level++;	first[level] = last[level] = '"';			break;
+			case '\'':
+				level++;	first[level] = last[level] = '\'';			break;
+			case '{':
+				level++;	first[level] = '{';		last[level] = '}';	break;
+			case '(':
+				level++;	first[level] = '(';		last[level] = ')';	break;
+				}
+			}
+		}
+	return res;
+}
+
 static symrec *curr_sym;
 static int yylex (void)
 {
 	int i, c, tok;
 	unsigned int h_nam, h2_nam;
-	char tmp_txt[80];
+	char tmp_txt[80], *block;
 	symrec *s;
 
 	while((c = buffer[buff_pos++]) == ' ' || c == '\t');	//get first nonwhite char
 	if(!c) return 0;
 	//test for block statement
 	if(c == '{') {
-		for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != '}')); buff_pos++) {
-			tmp_txt[i++] = (char)tok;
+		if(block = copy_block()) {
+			yylval.text = PushString(block);
+			free(block);
 			}
-		if(buffer[buff_pos] == '}')buff_pos++;
-		tmp_txt[i] = 0;
-		yylval.text = PushString(tmp_txt);
 		return yylval.type = BLOCK;
 		}
 	//test for '..' operator
@@ -1827,7 +2095,7 @@ static int yylex (void)
 		return yylval.type = SER;
 		}
 	//test for number
-	if(c == '.' || isdigit(c)) {
+	if(c > 31 &&(c == '.' || isdigit(c))) {
 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) {
 			tmp_txt[i++] = (char)c;
 			if(i && buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){
@@ -1844,8 +2112,8 @@ static int yylex (void)
 		return yylval.type = NUM;
 		}
 	//test for name or stringtoken
-	if(isalpha(c) || c=='$') {
- 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && (isalnum(c) || c == '$')); buff_pos++) {
+	if(c > 31 && (isalpha(c) || c=='$')) {
+ 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
 			tmp_txt[i++] = (char)c; 
 			}
 		tmp_txt[i] = 0;
@@ -1906,6 +2174,13 @@ static int yylex (void)
 		pop_syntax();
 		break;
 	case '(':
+		if(syntax_level->last_tok == WHILE){
+			if(block = copy_block()) {
+				yylval.text = PushString(block);
+				free(block);
+				}
+			return yylval.type = PBLOCK;
+			}
 		push_syntax();
 	case '?':
 		if(syntax_level) syntax_level->last_tok = c;
@@ -1932,6 +2207,7 @@ static int yylex (void)
 		buff_pos++;		return tok;
 		}
 	//Any other character is a token by itself
+	if(c < 0 || c > 127)yytokenerr(c);
 	return c;
 }
 
@@ -1958,7 +2234,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	push_parser();
 	init_table();
 	if(param) {
-		length = strlen(param);
+		length = (int)strlen(param);
 		if(!(buffer = (char*)malloc(length+2))){
 			pop_parser();
 			return false;
@@ -1970,7 +2246,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			}while(buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
-	length = strlen(expr);
+	length = (int)strlen(expr);
 	buffer = expr;		sx = putsym(hn_x, h2_x, VAR);
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
@@ -2017,7 +2293,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	push_parser();
 	init_table();
 	if(param) {
-		length = strlen(param);
+		length = (int)strlen(param);
 		if(!(buffer = (char*)malloc(length+2))){
 			pop_parser();
 			return false;
@@ -2029,7 +2305,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			}while(buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
-	length = strlen(expr);		buffer = expr;
+	length = (int)strlen(expr);		buffer = expr;
 	sx = putsym(hn_x, h2_x, VAR);	sz = putsym(hn_z, h2_z, VAR);
 	nr = iround((z2-z1)/zstep)+1;	nc = iround((x2-x1)/xstep)+1;
 	d->Init(nr, nc);
@@ -2073,7 +2349,7 @@ anyResult *do_formula(DataObj *d, char *expr)
 		return &ret;
 		}
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(expr);
+	init_table();		length = (int)strlen(expr);
 	if(!(buffer = (char*)malloc(length+2))){
 		pop_parser();
 		return &ret;
@@ -2099,20 +2375,21 @@ anyResult *do_formula(DataObj *d, char *expr)
 
 bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 {
-	int length, tok, pos, i;
+	int length, length2, tok, pos, i;
 	char *res, desc1[2], desc2[2];
 
 	if(d) curr_data = d;
 	if(!curr_data || !of || !nf) return false;
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(of);
+	init_table();		length = (int)strlen(of);
 	if(!(buffer = (char*)malloc(length+2))){
 		pop_parser();
 		return false;
 		}
 	strcpy(buffer, of);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = pos = 0;
-	res = (char *)calloc(length*2+10, sizeof(char));
+	if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false;
+	length2--;
 	do {
 		tok = yylex ();
 		if(tok && tok < 256) {
@@ -2121,97 +2398,121 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			}
 		else switch(tok) {
 			case NUM:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, 20, "%g", yylval.val);
+#else
 				pos += sprintf(res+pos, "%g", yylval.val);
+#endif
 				break;
 			case FNCT:	case FUNC1:	case FUNC2:	case FUNC3:	case AFNCT:
 			case SFNCT:	case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:
-				pos += sprintf(res+pos, "%s", curr_sym->name);
+			case YYFNC2:	case YYFNC3:
+				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case COLR:			case COLC:
-				pos += sprintf(res+pos, ":");
+				res[pos++] = ':';
 				break;
 			case PSEP:
-				pos += sprintf(res+pos, ";");
+				res[pos++] = ';';
 				break;
 			case CLVAL:
-				pos += sprintf(res+pos, "$$");
+				res[pos++] = '$';	res[pos++] = '$';
 				break;
 			case CLAUSE:
-				pos += sprintf(res+pos, " where ");
+				pos += rlp_strcpy(res+pos, length2-pos, " where ");
 				break;
 			case VAR:
 				curr_sym->InitSS();
 				if(curr_sym->col >= 0 && curr_sym->row >= 0) {
 					desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0;
-					for(i=strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
+					for(i=(int)strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
 					if(curr_sym->name[0] == '$') desc1[0] = '$';
 					if(curr_sym->name[i] == '$') desc2[0] = '$';
+#ifdef USE_WIN_SECURE
+					pos += sprintf_s(res+pos, length2-pos, "%s%s%s%d", desc1,
+#else
 					pos += sprintf(res+pos, "%s%s%s%d", desc1, 
+#endif
 						Int2ColLabel(desc1[0] || curr_sym->col < c0 ? curr_sym->col : curr_sym->col+dx >=0 ?
 						curr_sym->col+dx > c0 ? curr_sym->col+dx : c0 : 0, false),
 						desc2, desc2[0] || curr_sym->row < r0 ? curr_sym->row+1 : curr_sym->row + dy >= 0 ? 
 						curr_sym->row+dy > r0 ? curr_sym->row+1+dy : r0 : 1);
 					}
-				else pos += sprintf(res+pos, "%s ", curr_sym->name);
+				else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case STR:
 				pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
 				break;
 			case SER:
-				pos += sprintf(res+pos, "..");
+				res[pos++] = '.';	res[pos++] = '.';
 				break;
 			case INC:
-				pos += sprintf(res+pos, "++");
+				res[pos++] = '+';	res[pos++] = '+';
 				break;
 			case DEC:
-				pos += sprintf(res+pos, "--");
+				res[pos++] = '-';	res[pos++] = '-';
 				break;
 			case PI:
-				pos += sprintf(res+pos, "pi");
+				res[pos++] = 'p';	res[pos++] = 'i';
 				break;
 			case E:
-				pos += sprintf(res+pos, "e");
+				res[pos++] = 'e';
 				break;
 			case BTRUE:
-				pos += sprintf(res+pos, "true");
+				pos += rlp_strcpy(res+pos, length2-pos, "true");
 				break;
 			case BFALSE:
-				pos += sprintf(res+pos, "false");
+				pos += rlp_strcpy(res+pos, length2-pos, "false");
 				break;
 			case AND:
-				pos += sprintf(res+pos, " && ");
+				pos += rlp_strcpy(res+pos, length2-pos, " && ");
 				break;
 			case OR:
-				pos += sprintf(res+pos, " || ");
+				pos += rlp_strcpy(res+pos, length2-pos, " || ");
 				break;
 			case EQ:
-				pos += sprintf(res+pos, " == ");
+				pos += rlp_strcpy(res+pos, length2-pos, " == ");
 				break;
 			case NE:
-				pos += sprintf(res+pos, " != ");
+				pos += rlp_strcpy(res+pos, length2-pos, " != ");
 				break;
 			case GT:
-				pos += sprintf(res+pos, ">");
+				res[pos++] = '>';
 				break;
 			case GE:
-				pos += sprintf(res+pos, ">=");
+				res[pos++] = '>';	res[pos++] = '=';
 				break;
 			case LT:
-				pos += sprintf(res+pos, "<");
+				res[pos++] = '<';
 				break;
 			case LE:
-				pos += sprintf(res+pos, "<=");
+				res[pos++] = '<';	res[pos++] = '=';
 				break;
 			case IF: 
-				pos += sprintf(res+pos, "if");
+				res[pos++] = 'i';	res[pos++] = 'f';
+				break;
+			case WHILE: 
+				pos += rlp_strcpy(res+pos, length2-pos, "while");
 				break;
 			case ELSE: 
-				pos += sprintf(res+pos, "else");
+				pos += rlp_strcpy(res+pos, length2-pos, "else");
 				break;
 			case BLOCK:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
+#else
 				pos += sprintf(res+pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
+#endif
+				break;
+			case PBLOCK:
+#ifdef USE_WIN_SECURE
+				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
+#else
+				pos += sprintf(res+pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
+#endif
 				break;
 			}
+		res[pos] = 0;
 		}while(buff_pos < length);
 	while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} 
 	strcpy(nf, res);	free(res);
@@ -2238,7 +2539,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 	//calc result
 	symx->SetValue(x);	symz->SetValue(z);	
 	buffer = txt_formula;
-	buff_pos = 0;		length = strlen(txt_formula);
+	buff_pos = 0;		length = (int)strlen(txt_formula);
 	do {	yyparse();	}while(buff_pos < length);
 	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
@@ -2323,7 +2624,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		}
 	//common initialization for parser tasks
 	push_parser();		//make code reentrant
-	init_table();		length = strlen(*par);
+	init_table();		length = (int)strlen(*par);
 	//process parameters
 	if(!(buffer = (char*)malloc(length+2))){
 		clear_table();	pop_parser();
@@ -2372,10 +2673,11 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
 		j += l;			k += l;
 		}
-	free(*par);	*par = strdup(tmp_txt);
+	free(*par);
+	*par = (char*)memdup(tmp_txt, (int)strlen(tmp_txt)+1, 0);
 	if(chi_2) *chi_2 = chisq;
 	//write back spreadsheet data if necessary
-	buffer = *par;	length = strlen(buffer);
+	buffer = *par;	length = (int)strlen(buffer);
 	do {
 		yyparse();
 		}while(buff_pos < length);
@@ -2394,11 +2696,3 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
-
-
-
-
-
-
-
-
diff --git a/no_gui.cpp b/no_gui.cpp
index 5199654..eee8d1d 100755
--- a/no_gui.cpp
+++ b/no_gui.cpp
@@ -130,7 +130,7 @@ FrmRect::SetColor(int select, DWORD col)
 	return false;
 }
 
-void 
+void
 FrmRect::DoMark(anyOutput *o, bool mark)
 {
 }
@@ -172,7 +172,7 @@ bool GetPaper(double *w, double *h)
 	*w = *h = 1.0;
 	return true;
 }
- 
+
 bool Symbol::PropertyDlg()
 {
 	return false;
@@ -218,7 +218,7 @@ bool Arrow::PropertyDlg()
 	return false;
 }
 
-void * 
+void *
 Arrow::ObjThere(int x, int y)
 {
 	return 0L;
@@ -279,19 +279,29 @@ bool Label::PropertyDlg()
 	return false;
 }
 
-void
-Label::ShowCursor(anyOutput *o)
+void Label::ShowCursor(anyOutput *o)
 {
 }
 
-bool
-Label::AddChar(int ci, anyOutput *o)
+bool Label::AddChar(int ci, anyOutput *o)
 {
 	return true;
 }
 
-void
-Label::CalcCursorPos(int x, int y, anyOutput *o)
+void Label::CalcCursorPos(int x, int y, anyOutput *o)
+{
+}
+
+bool TextFrame::PropertyDlg()
+{
+	return false;
+}
+
+void TextFrame::ShowCursor(anyOutput *o)
+{
+}
+
+void TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
 {
 }
 
@@ -547,4 +557,4 @@ bool DelBitmapClass(anyOutput *w)
 {
 	return false;
 }
-
+
diff --git a/reports.cpp b/reports.cpp
index bff14c5..ab73a4d 100755
--- a/reports.cpp
+++ b/reports.cpp
@@ -18,25 +18,30 @@
 //
 // Create statistical reports
 //
-
+
 #include "rlplot.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <math.h>
+#include <ctype.h>
 #include "TheDialog.h"
 
 extern char TmpTxt[];
 extern Default defs;
+extern GraphObj *LastOpenGO;
+
+#define _PREC 1.0e-12
 
 //prototypes: WinSpec.cpp
 void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
 
-static int curr_id;
+static int curr_id, cbSymLineStr;
 static fRECT dBounds;
 static TextDEF txtdef1, txtdef2;
 static double linsp1, linsp2;
+static char SymLineStr[40];
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // init report variables
@@ -59,46 +64,61 @@ static void rep_init()
 #ifdef _WINDOWS
 	linsp1 = txtdef1.fSize*1.2;	linsp2 = txtdef1.fSize*1.5;
 #else
-	linsp1 = txtdef1.fSize*1.5;	linsp2 = txtdef1.fSize*2.0;
+	linsp1 = txtdef1.fSize*1.7;	linsp2 = txtdef1.fSize*2.5;
+#endif
+#ifdef USE_WIN_SECURE
+	cbSymLineStr = sprintf_s(SymLineStr, 40, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE)); 
+#else
+	cbSymLineStr = sprintf(SymLineStr, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE)); 
 #endif
-
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// utility to add a line to a text buffer
+// create a text label for a report
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void add_to_buff(char** dest, int *pos, int *csize, char *txt)
+static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td, char*text)
 {
-	int len;
+	int csize, pos = 0;
+	char *res;
 
-	len = strlen(txt);
-	if((*pos+len+1)>= *csize) {
-		*dest = (char*)realloc(*dest, *csize += 1000);
-		}
-	if(*dest) {
-		*pos += sprintf(*dest+*pos, "%s", txt);
-		}
+	if(!(res = (char*)malloc(csize = 1000)))return 0L;
+	res[pos++] = '\n';				res[pos++] = '[';
+	add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+	add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+	add_dbl_to_buff(&res, &pos, &csize, x, true);
+	add_dbl_to_buff(&res, &pos, &csize, y, true);
+	res[pos++] = '\n';
+	if(moveable) add_to_buff(&res, &pos, &csize, "moveable= 1\n", 12);
+	add_to_buff(&res, &pos, &csize, "TxtDef= 0x0 0x00ffffff", 22);
+	add_dbl_to_buff(&res, &pos, &csize, td->fSize, true);
+	add_dbl_to_buff(&res, &pos, &csize, td->RotBL, true);
+	add_dbl_to_buff(&res, &pos, &csize, td->RotCHAR, true);
+	add_int_to_buff(&res, &pos, &csize, align, true, 0);
+	add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+	add_to_buff(&res, &pos, &csize, text, 0);
+	add_to_buff(&res, &pos, &csize, "\"\n", 2);
+	return res;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a text label for a report
+// print values to string
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td, char*text)
+static int dbl_to_str1(char *dest, int size, char* fmt, double val)
 {
-	int csize, pos = 0;
-	char *res, line[120];
+#ifdef USE_WIN_SECURE
+	return sprintf_s(dest, size, fmt, val);
+#else
+	return sprintf(dest, fmt, val);
+#endif
+}
 
-	if(!(res = (char*)malloc(csize = 1000)))return 0L;
-	sprintf(line, "\n[%d=Label]\nPos= %g %g\n", curr_id++, x, y);
-	add_to_buff(&res, &pos, &csize, line);
-	if(moveable) {
-		sprintf(line, "moveable= 1\n");
-		add_to_buff(&res, &pos, &csize, line);
-		}
-	sprintf(line, "TxtDef= 0x00000000 0x00ffffff %g %g %g %d 1 0 0 \"%s\"\n",
-		td->fSize, td->RotBL, td->RotCHAR, align, text);
-	add_to_buff(&res, &pos, &csize, line);
-	return res;
+static int dbl_to_str2(char *dest, int size, char* fmt, double val1, double val2)
+{
+#ifdef USE_WIN_SECURE
+	return sprintf_s(dest, size, fmt, val1, val2);
+#else
+	return sprintf(dest, fmt, val1, val2);
+#endif
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -109,6 +129,7 @@ static void mk_header(Page *page, char* desc)
 	time_t ti = time(0L);
 	char *txt_obj, label[80];
 	double rpos;
+	int cb;
 
 	if(!page) return;
 	rpos = page->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0;
@@ -117,12 +138,19 @@ static void mk_header(Page *page, char* desc)
 		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
 		free(txt_obj);
 		}
+#ifdef USE_WIN_SECURE
+	ctime_s(label, 32, &ti);
+#else
+	rlp_strcpy(label, 25, ctime(&ti));
+#endif
+	label[24] = 0;
 	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
-		false, TXA_HRIGHT, &txtdef1, ctime(&ti))) {
+		false, TXA_HRIGHT, &txtdef1, label)) {
 		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
 		free(txt_obj);
 		}
-	sprintf(label, "RLPlot %s", SZ_VERSION);
+	cb = rlp_strcpy(label, 80, "RLPlot ");
+	cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
 	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
 		false, TXA_HRIGHT, &txtdef1, label)) {
 		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
@@ -136,18 +164,96 @@ static void mk_header(Page *page, char* desc)
 static void mk_hr(GraphObj *parent, double x1, double x2, double y)
 {
 	int csize, pos = 0;
-	char *res, line[120];
+	char *res;
 
-	if(!(res = (char*)malloc(csize = 1000)))return;
-	sprintf(line, "\n[%d=polyline]\nData=(2){ %g %g %g %g}\n", curr_id++, x1, y, x2, y);
-	add_to_buff(&res, &pos, &csize, line);
-	sprintf(line, "Line= %g %g 0x0 0x0\n", txtdef1.fSize/20.0, txtdef1.fSize);
-	add_to_buff(&res, &pos, &csize, line);
+	if(!(res = (char*)malloc(csize = 100)))return;
+	res[pos++] = '\n';				res[pos++] = '[';
+	add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+	add_to_buff(&res, &pos, &csize, "=polyline]\nData= (2){", 21);
+	add_dbl_to_buff(&res, &pos, &csize, x1, false);
+	add_dbl_to_buff(&res, &pos, &csize, y, true);
+	add_dbl_to_buff(&res, &pos, &csize, x2, true);
+	add_dbl_to_buff(&res, &pos, &csize, y, true);
+	add_to_buff(&res, &pos, &csize, "}\nLine=", 7);
+	add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/20.0, true);
+	add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+	add_to_buff(&res, &pos, &csize, " 0x0 0x0\n", 9);
 	OpenGraph(parent, 0L, (unsigned char*)res, false);
 	free(res);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a means report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_mean_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
+{
+	static char *mean_fmts[] = {"Mean = %g", "Std.Dev. = %g", "N = %g", "Std.Err. = %g", 0L,
+		"Kurtosis = %g", "Skewness = %g"};
+	char *txt_obj, desc[80];
+	int i, cb;
+	double v, t, res[10];
+
+	cb = rlp_strcpy(desc, 20, "<b>");				cb += rlp_strcpy(desc+cb, 20-cb, name);
+	cb += rlp_strcpy(desc+cb, 20-cb, ":</b>");
+	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);								y += linsp1;
+		}
+	x += (txtdef1.fSize*3.0);
+	cb = dbl_to_str1(desc, 80, "%g%%%% C.I. = %%g", ci*100.0);
+	mean_fmts[4] = (char*)malloc(cb+2);
+	rlp_strcpy(mean_fmts[4], cb+1, desc);			t = distinv(t_dist, n-1, 1, 1.0-ci, 2.0);
+	v = d_variance(n, da, &res[0], 0L);				res[2] = (double)n;
+	res[1] = sqrt(v);								res[3] = res[1] / sqrt(res[2]);
+	res[4] = res[3] *t;								res[5] = d_kurt(n, da);
+	res[6] = d_skew(n, da);
+	for(i = 0; i < 7; i++) {
+		dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
+		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
+			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);							y += linsp1/1.2;
+			}
+		if(i == 2) y += linsp1/3.6;
+		}
+	free(mean_fmts[4]);								mean_fmts[4] = 0L;
+	return y;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a median report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_median_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
+{
+	static char *mean_fmts[] = {"Median = %g", "25%% = %g", "75%% = %g", "N = %g", "Min. = %g", "Max. = %g" };
+	char *txt_obj, desc[80];
+	int i, cb;
+	double res[6];
+
+	if(!da || !parent || !n) return y;
+	cb = rlp_strcpy(desc, 20, "<b>");				cb += rlp_strcpy(desc+cb, 20-cb, name);
+	cb += rlp_strcpy(desc+cb, 20-cb, ":</b>");
+	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);								y += linsp1;
+		}
+	x += (txtdef1.fSize*3.0);
+	d_quartile(n, da, &res[1], &res[0], &res[2]);
+	res[4] = res[5] = *da;
+	for(i = 1; i < n; i++) {
+		if(da[i] > res[5]) res[5] = da[i];			if(da[i] < res[4]) res[4] = da[i];
+		}
+	res[3] = (double)n;
+	for(i = 0; i < 6; i++) {
+		dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
+		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
+			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);							y += linsp1/1.2;
+			}
+		}
+	return y;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create report table for anova ...
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static void mk_table(GraphObj *parent, double x, double y, int type, double **dda)
@@ -157,15 +263,20 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 		(char*)"Among groups", type == 2 ? (char*)"Unexplained":(char*)"Within groups", "Total"};
 	char *cfmt[8];
 	int i, j, nl, nc[8];
-	double posc[8];
+	double posc[8], cinc;
 	char *txt_obj;
 
+#ifdef _WINDOWS
+	cinc = txtdef1.fSize;
+#else
+	cinc = txtdef1.fSize *1.3;
+#endif
 	switch(type) {
 	case 1:	case 2:
 		nl = 3;	nc[0] = 5;	nc[1] = 3;	nc[2] = 2;
-		posc[0] = x + txtdef1.fSize*14.0;		posc[1] = posc[0] + txtdef1.fSize*5.0;
-		posc[2] = posc[1] + txtdef1.fSize*6.0;	posc[3] = posc[2] + txtdef1.fSize*6.0;
-		posc[4] = posc[3] + txtdef1.fSize*6.0;	cfmt[0] = "%.0lf";
+		posc[0] = x + cinc*14.0;		posc[1] = posc[0] + cinc*5.0;
+		posc[2] = posc[1] + cinc*6.0;	posc[3] = posc[2] + cinc*6.0;
+		posc[4] = posc[3] + cinc*6.0;	cfmt[0] = "%.0lf";
 		cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));	
 		cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[0][1])-3.0));
 		cfmt[3] = "%0.3lf";						cfmt[4] = "%0.4lf";
@@ -185,7 +296,7 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 			if(i) posc[i] += linsp1;
 			}
 		mk_hr(parent, x, posc[4], y + linsp1);
-		y += (txtdef1.fSize *1.5);
+		y += linsp2;
 		}
 	for(i = 0; i < nl; i++) {
 		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1])) {
@@ -194,8 +305,12 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 			}
 		for(j = 0; j < nc[i]; j++) {
 			if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001)
-				strcpy(TmpTxt, "< 0.0001");
+				rlp_strcpy(TmpTxt, 10, "< 0.0001");
+#ifdef USE_WIN_SECURE
+			else sprintf_s(TmpTxt, 20, cfmt[j], dda[i][j]);
+#else
 			else sprintf(TmpTxt, cfmt[j], dda[i][j]);
+#endif
 			if(txt_obj = mk_label(posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt)) {
 				OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
 				free(txt_obj);
@@ -210,81 +325,211 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a boxplot for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *wy1, double *wy2, int *ny, int n, 
+	char *s_nam, char *b_nam, char *w_nam)
+{
+	int i, csize, pos, first_s, first_b, first_w, first_l;
+	char *res;
+	double size;
+
+	if(!(res = (char*)malloc(csize = 2000)))return 0L;
+	if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
+	else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
+	first_b = curr_id;
+	for(i = pos = 0; i < n && res; i++) {
+		add_to_buff(&res, &pos, &csize, "\n[", 2);		add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+		add_to_buff(&res, &pos, &csize, "=Box]\nType= 256\nHigh=", 21);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
+		add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
+		add_to_buff(&res, &pos, &csize,"\nSize= 60\n", 10);
+		add_to_buff(&res, &pos, &csize, "\nName= \"", 8);
+		add_to_buff(&res, &pos, &csize, b_nam, 0);
+		add_to_buff(&res, &pos, &csize, "\"\n", 2);
+		}
+	first_w = curr_id;
+	for(i = 0; i < n && res; i++) {
+		add_to_buff(&res, &pos, &csize, "\n[", 2);		add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+		add_to_buff(&res, &pos, &csize, "=Whisker]\nHigh=", 15);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+		add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
+		add_to_buff(&res, &pos, &csize, "\nDesc= \"", 8);
+		add_to_buff(&res, &pos, &csize, w_nam, 0);
+		add_to_buff(&res, &pos, &csize, "\"\n", 2);
+		}
+	first_s = curr_id;
+	for(i = 0; i < n && res; i++) {
+		add_to_buff(&res, &pos, &csize, "\n[", 2);		add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+		add_to_buff(&res, &pos, &csize, "=Symbol]\nType= 10\nPos=", 22);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+		add_to_buff(&res, &pos, &csize, "\nSize=", 6);	add_dbl_to_buff(&res, &pos, &csize, size, true);
+		add_to_buff(&res, &pos, &csize, "\n", 1);
+		add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
+		add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
+		if(s_nam) {
+			add_to_buff(&res, &pos, &csize, "Name=\"", 6);
+			add_to_buff(&res, &pos, &csize, s_nam, 0);	add_to_buff(&res, &pos, &csize, "\"\n", 2);
+			}
+		}
+	first_l = curr_id;
+	for(i = 0; i < n && res; i++) {
+		add_to_buff(&res, &pos, &csize, "\n[", 2);
+		add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+		add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+		add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
+		add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
+		add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
+		add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+		add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
+		add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
+		add_int_to_buff(&res, &pos, &csize, TXA_HCENTER | TXA_VBOTTOM, true, 0);
+		add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+		if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
+		add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
+		add_to_buff(&res, &pos, &csize, "\"\n", 2);
+		}
+	add_to_buff(&res,&pos,&csize, "\n[", 2);				add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
+	add_to_buff(&res, &pos, &csize, "=BoxPlot]\nBounds=", 17);
+	add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true);	add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
+	add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true);	add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
+
+	add_to_buff(&res,&pos,&csize, "\nBoxes=(", 0);			add_int_to_buff(&res,&pos,&csize, n, false, 0);
+	add_to_buff(&res,&pos,&csize, "){", 2);
+	for(i = 0; i < n; i++, first_b++) {
+		add_int_to_buff(&res,&pos,&csize, first_b, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
+		if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
+		}
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	add_to_buff(&res,&pos,&csize, "\nWhiskers=(", 0);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
+	add_to_buff(&res,&pos,&csize, "){", 2);
+	for(i = 0; i < n; i++, first_w++) {
+		add_int_to_buff(&res,&pos,&csize, first_w, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
+		if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
+		}
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
+	add_to_buff(&res,&pos,&csize, "){", 2);
+	for(i = 0; i < n; i++, first_s++) {
+		add_int_to_buff(&res,&pos,&csize, first_s, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
+		if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
+		}
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	add_to_buff(&res,&pos,&csize, "\nLabels=(", 9);			add_int_to_buff(&res,&pos,&csize, n, false, 0);
+	add_to_buff(&res,&pos,&csize, "){", 2);
+	for(i = 0; i < n; i++, first_l++) {
+		add_int_to_buff(&res,&pos,&csize, first_l, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
+		if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
+		}
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create a scatterplot for a report
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n)
+static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_nam, char *x_desc, char *y_desc)
 {
 	int i, csize, pos, first;
-	char *res, line[80];
+	char *res;
 	double size, linew, tmp;
 
-	if(!(res = (char*)malloc(csize = 1000)))return 0L;
+	if(!(res = (char*)malloc(csize = 2000)))return 0L;
 	if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
 	else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
 	linew = defs.GetSize(SIZE_SYM_LINE);
 	first = curr_id;
 	for(i = pos = 0; i < n && res; i++) {
-		sprintf(line, "\n[%d=Symbol]\nPos= %g %g\n", curr_id++, x ? x[i] : (double)(i+1), y[i]);
-		add_to_buff(&res, &pos, &csize, line);
-		sprintf(line, "Size= %g\n", size);
-		add_to_buff(&res, &pos, &csize, line);
-		sprintf(line, "Line= %g 1 0x0 0x0\nFillCol= 0x00ffffff\n", linew);
-		add_to_buff(&res, &pos, &csize, line);
+		add_to_buff(&res, &pos, &csize, "\n[", 2);		add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+		add_to_buff(&res, &pos, &csize, "=Symbol]\nPos=", 13);
+		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+		add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+		add_to_buff(&res, &pos, &csize, "\nSize=", 6);	add_dbl_to_buff(&res, &pos, &csize, size, true);
+		add_to_buff(&res, &pos, &csize, "\n", 1);
+		add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
+		add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
+		if(s_nam) {
+			add_to_buff(&res, &pos, &csize, "Name=\"", 6);
+			add_to_buff(&res, &pos, &csize, s_nam, 0);	add_to_buff(&res, &pos, &csize, "\"\n", 2);
+			}
 		}
 	if(ss && ny) {
 		for(i = 0; i < n && res; i++) {
 			if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
 			else tmp = 0.0;
-			sprintf(line, "\n[%d=ErrorBar]\nPos= %g %g\n", curr_id++, x ? x[i] : (double)(i+1), y[i]);
-			add_to_buff(&res, &pos, &csize, line);
-			sprintf(line, "Err= %g\nDesc= \"Std. Dev.\"\n", tmp);
-			add_to_buff(&res, &pos, &csize, line);
+			add_to_buff(&res, &pos, &csize, "\n[", 2);
+			add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+			add_to_buff(&res, &pos, &csize, "=ErrorBar]\nPos=", 15);
+			add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+			add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+			add_to_buff(&res, &pos, &csize, "\nErr=", 5);
+			add_dbl_to_buff(&res, &pos, &csize, tmp, true);
+			add_to_buff(&res, &pos, &csize, "\nDesc= \"Std. Dev.\"\n", 19);
 			}
 		for(i = 0; i < n && res; i++) {
 			if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
 			else tmp = 0.0;
-			sprintf(line, "\n[%d=Label]\nPos= %g %g\n", curr_id++, x ? x[i]:(double)(i+1), y[i] +tmp);
-			add_to_buff(&res, &pos, &csize, line);
-			sprintf(line, "Dist= 0 %g\nFlags= 0x00000011\n", -txtdef1.fSize/4.0);
-			add_to_buff(&res, &pos, &csize, line);
-			sprintf(line, "TxtDef= 0x00000000 0x00ffffff %g %g %g %d 1 0 0 \"%s%d\"\n",
-				txtdef1.fSize, txtdef1.RotBL, txtdef1.RotCHAR, TXA_HCENTER | TXA_VBOTTOM, 
-				n > 6 ? "" : "n = ", ny[i]);
-			add_to_buff(&res, &pos, &csize, line);
+			add_to_buff(&res, &pos, &csize, "\n[", 2);
+			add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+			add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+			add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+			add_dbl_to_buff(&res, &pos, &csize, y[i] +tmp, true);
+			add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
+			add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
+			add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
+			add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+			add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
+			add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
+			add_int_to_buff(&res, &pos, &csize, TXA_HCENTER | TXA_VBOTTOM, true, 0);
+			add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+			if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
+			add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
+			add_to_buff(&res, &pos, &csize, "\"\n", 2);
 			}
 		}
-	sprintf(line, "\n[%d=PlotScatt]\n", curr_id++);
-	add_to_buff(&res, &pos, &csize, line);
-	sprintf(line, "Bounds= %g %g %g %g\n", dBounds.Xmin, dBounds.Ymax, dBounds.Xmax, dBounds.Ymin);
-	add_to_buff(&res, &pos, &csize, line);
-	sprintf(line, "Symbols=(%d){", n);		add_to_buff(&res, &pos, &csize, line);
+	add_to_buff(&res,&pos,&csize, "\n[", 2);				add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
+	add_to_buff(&res, &pos, &csize, "=PlotScatt]\nBounds=", 19);
+	add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true);	add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
+	add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true);	add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
+	add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
+	add_to_buff(&res,&pos,&csize, "){", 2);
 	for(i = 0; i < n; i++, first++) {
-		sprintf(line, "%s%d", i ? "," : "", first);
-		add_to_buff(&res, &pos, &csize, line);
-		if(i && (i%16) && first < (curr_id-2)) {
-			sprintf(line, "\n   ");			add_to_buff(&res, &pos, &csize, line);
-			}
+		add_int_to_buff(&res,&pos,&csize, first, false,0);	add_to_buff(&res,&pos,&csize, ",", 1);
+		if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 		}
-	sprintf(line, "}\n");					add_to_buff(&res, &pos, &csize, line);
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
 	if(ss && ny) {
-		sprintf(line, "ErrBars=(%d){", n);	add_to_buff(&res, &pos, &csize, line);
+		add_to_buff(&res,&pos,&csize, "ErrBars=(", 9);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
+		add_to_buff(&res,&pos,&csize, "){", 2);
 		for(i = 0; i < n; i++, first++) {
-			sprintf(line, "%s%d", i ? "," : "", first);
-			add_to_buff(&res, &pos, &csize, line);
-			if(i && (i%16) && first < (curr_id-2)) {
-				sprintf(line, "\n   ");		add_to_buff(&res, &pos, &csize, line);
-				}
+			add_int_to_buff(&res,&pos,&csize, first,false,0);	add_to_buff(&res,&pos,&csize, ",", 1);
+			if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 			}
-		sprintf(line, "}\n");				add_to_buff(&res, &pos, &csize, line);
-		sprintf(line, "Labels=(%d){", n);	add_to_buff(&res, &pos, &csize, line);
+		while(res[pos-1] == ',' || res[pos-1] < 33) pos --;	add_to_buff(&res, &pos, &csize, "}\n", 2);
+		add_to_buff(&res,&pos,&csize, "Labels=(", 8);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
+		add_to_buff(&res,&pos,&csize, "){", 2);
 		for(i = 0; i < n; i++, first++) {
-			sprintf(line, "%s%d", i ? "," : "", first);
-			add_to_buff(&res, &pos, &csize, line);
-			if(i && (i%16) && first < (curr_id-2)) {
-				sprintf(line, "\n   ");		add_to_buff(&res, &pos, &csize, line);
-				}
+			add_int_to_buff(&res,&pos,&csize, first,false,0);	add_to_buff(&res,&pos,&csize, ",", 1);
+			if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 			}
-		sprintf(line, "}\n");				add_to_buff(&res, &pos, &csize, line);
+		while(res[pos-1] == ',' || res[pos-1] < 33) pos --;	add_to_buff(&res, &pos, &csize, "}\n", 2);
+		}
+	if(x_desc && x_desc[0]){
+		add_to_buff(&res,&pos,&csize, "x_info= \"", 9);		add_to_buff(&res,&pos,&csize, x_desc, 0);
+		add_to_buff(&res,&pos,&csize, "\"\n", 2);
+		}
+	if(y_desc && y_desc[0]){
+		add_to_buff(&res,&pos,&csize, "y_info= \"", 9);		add_to_buff(&res,&pos,&csize, y_desc, 0);
+		add_to_buff(&res,&pos,&csize, "\"\n", 2);
 		}
 	return res;
 }
@@ -323,16 +568,18 @@ rep_anova(GraphObj *parent, DataObj *data)
 
 	if(!parent || !data) return;
 	if(!(AnovaDlg = CompileDialog(AnovaDlg_Tmpl, dyndata))) return;
-	if(data->Command(CMD_GETMARK, &mrk, 0L)) {
-		strcpy(TmpTxt, mrk);
-		}
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
 	else {
 		data->ValueRec(&rec);
+#ifdef USE_WIN_SECURE
+		i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", Int2ColLabel(rec.left,false), rec.top + 1);
+		sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, ":%s%d", Int2ColLabel(rec.right, false), rec.bottom+1);
+#else
 		i = sprintf(TmpTxt,"%s%d", Int2ColLabel(rec.left,false), rec.top + 1);
 		sprintf(TmpTxt+i, ":%s%d", Int2ColLabel(rec.right, false), rec.bottom+1);
+#endif
 		}
-	if(!(Dlg = new DlgRoot(AnovaDlg)))return;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
 	hDlg = CreateDlgWnd("One Way Anova", 50, 50, 420, 220, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -347,7 +594,7 @@ rep_anova(GraphObj *parent, DataObj *data)
 			break;
 			}
 		}while (res < 0);
-	if(res == 1 && Dlg->GetText(101, TmpTxt) &&(rD = new AccRange(TmpTxt))
+	if(res == 1 && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) &&(rD = new AccRange(TmpTxt))
 		&& rD->BoundRec(&rec) && (res_tab = (double**)calloc(3, sizeof(double*)))
 		&& (res_tab[0] = (double*) malloc(5*sizeof(double)))
 		&& (res_tab[1] = (double*) malloc(5*sizeof(double)))
@@ -370,7 +617,7 @@ rep_anova(GraphObj *parent, DataObj *data)
 				for(i = rec.top; i <= rec.bottom; i++) {
 					ncols[i-rec.top] = 0;	cols[i-rec.top] = (double*)malloc(nr * sizeof(double));
 					if(cols[i-rec.top]) for(j = rec.left; j <= rec.right; j++) {
-						if(data->GetValue(j, i, &tmp)) cols[i-rec.top][ncols[i-rec.top]++] = tmp;
+						if(data->GetValue(i, j, &tmp)) cols[i-rec.top][ncols[i-rec.top]++] = tmp;
 						}
 					}
 				}
@@ -387,7 +634,7 @@ rep_anova(GraphObj *parent, DataObj *data)
 				mtot += csums[i];			ntot += ncols[i];
 				if(ncols[i]) csums[i] /= ((double)ncols[i]);
 				}
-			dBounds.Xmin = 0.0;				dBounds.Xmax = nc;
+			dBounds.Xmin = 0.5;				dBounds.Xmax = nc;
 			if(ntot) mtot /= ((double)ntot);
 			for(i = 0; i < nc; i++) {
 				for(j = 0, css[i] = 0.0; j < ncols[i]; j++) {
@@ -407,7 +654,7 @@ rep_anova(GraphObj *parent, DataObj *data)
 			res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
 			page = new Page(parent, data);
 			mk_header(page, "<b>One Way ANOVA</b>");
-			if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc))){
+			if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc, "Mean", 0L, "Means <u>+</u> S.D."))){
 				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
 				free(txt_obj);								graph->moveable = 0;
 				graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
@@ -434,6 +681,77 @@ rep_anova(GraphObj *parent, DataObj *data)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // linear regression analysis
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_regr_summary(GraphObj *parent, double x, double y, double *dres, double ci, int n)
+{
+	char *txt_obj;
+	char *fmts[] = {"slope = %g", "intercept = %g", "observations = %g", "r<sup> 2</sup> = %g", "r = %g"};
+	char *ci_fmt = "%g  -  %g";
+	char lbl[80];
+	double z, s;
+	double x1 = x + txtdef1.fSize*3.0;
+	double x2 = x + txtdef1.fSize*20.0;
+#ifdef _WINDOWS
+	double hrw = txtdef1.fSize*38.0;
+#else
+	double hrw = txtdef1.fSize*1.3*38.0;
+#endif
+
+	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, "<b>Regression:</b>")) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	dbl_to_str1(lbl, 80, "%g%% C.I.", ci);
+	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
+	y += linsp1*1.5;		dbl_to_str1(lbl, 80, fmts[0], dres[0]);
+	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	dbl_to_str2(lbl, 80, ci_fmt, dres[0]-dres[10], dres[0]+dres[10]);
+	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	y += linsp1;		dbl_to_str1(lbl, 80, fmts[1], dres[1]);
+	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	dbl_to_str2(lbl, 80, ci_fmt, dres[1]-dres[11], dres[1]+dres[11]);
+	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	y += linsp1;		dbl_to_str1(lbl, 80, fmts[2], (double)n);
+	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	y += linsp1;		dbl_to_str1(lbl, 80, fmts[3], dres[12]);
+	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	y += linsp1;		dbl_to_str1(lbl, 80, fmts[4], sqrt(dres[12]));
+	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	z = 0.5 * log((1.0+sqrt(dres[12])+_PREC)/(1.0-sqrt(dres[12])+_PREC));	//Fishers z-transform
+	s = distinv(t_dist, 1.0E+10, 1.0, (100-ci)/100.0, 2.0)/sqrt((double)(n-3));	
+	dbl_to_str2(lbl, 80, ci_fmt, tanh(z-s), tanh(z+s));
+	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
+	return y + linsp1*3.0;
+}
+
 static char *RegrDlg_Tmpl =
 	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
 	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
@@ -463,18 +781,17 @@ rep_regression(GraphObj *parent, DataObj *data)
 	int i, n, n1, rx, cx, ry, cy, res, align = 0;
 	bool bContinue = false, bParZ;
 	AccRange *rX = 0L, *rY = 0L;
-	double *x = 0L, *y = 0L, **res_tab = 0L;
+	double *x = 0L, *y = 0L, **res_tab = 0L, c_x, c_y;
 	double sx, sy, dx, dy, sxy, sxx, syy, sdy, df, t, ts, ty;
-	double dres[10], ly[4], regr_sum[5][3];
-	char *txt_obj;
+	double dres[14], ly[4];
+	char *txt_obj, *x_desc=0L, *y_desc=0L;
 	Graph *graph;
 	Page *page;
 
 	if(!parent || !data) return;
 	if(!(RegrDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
 	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
-	if(!(Dlg = new DlgRoot(RegrDlg)))return;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
 	hDlg = CreateDlgWnd("Linear Regression", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -489,16 +806,16 @@ rep_regression(GraphObj *parent, DataObj *data)
 			break;
 		case 1:
 			Dlg->GetValue(105, &ci);			bParZ = Dlg->GetCheck(107);
-			if(rX) delete rX;	if(rY) delete rY;
+			if(rX) delete rX;					if(rY) delete rY;
 			rX = rY = 0L;
-			if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
 			n = rX ? rX->CountItems() : 0;
 			if(!n) {
 				ErrorBox("range not specified\nor not valid.");
 				bContinue = true;
 				res = -1;
 				}
-			if(n && Dlg->GetText(103, TmpTxt) && (rY = new AccRange(TmpTxt))){
+			if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
 				if(n != rY->CountItems()) {
 					ErrorBox("both ranges must be given\nand must have the same size");
 					bContinue = true;
@@ -514,6 +831,7 @@ rep_regression(GraphObj *parent, DataObj *data)
 		&& (res_tab[0] = (double*) malloc(5*sizeof(double)))
 		&& (res_tab[1] = (double*) malloc(5*sizeof(double)))
 		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))) {
+		x_desc = rX->RangeDesc(data, 0);	y_desc = rY->RangeDesc(data, 0);
 		rX->GetFirst(&cx, &rx);				rY->GetFirst(&cy, &ry);
 		rep_init();
 		dBounds.Xmin = dBounds.Ymin = HUGE_VAL;		dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
@@ -550,21 +868,50 @@ rep_regression(GraphObj *parent, DataObj *data)
 		dres[5] = sxx/(n-1);			dres[6] = syy/(n-1);			dres[7] = sdy;
 		dres[8] = sxy/sdy*sxy/sxx;		dres[9] = f_dist(dres[8], 1.0, df);
 		t = distinv(t_dist, df, 1.0, (100.0-ci)/100.0, 2.0); 
+		dres[10] = t * sqrt(dres[7]/sxx);
+		dres[11] = t * sqrt(dres[7]*(dres[2]*dres[2]/sxx +1.0/(double)n));
 		if (n && (graph = new Graph(parent, data, 0L))) {
+			if(txt_obj = mk_scatt(x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				}
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
+				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Regression\"\n");
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
+				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n", 
+				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
+				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n", 
+				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+#else
 			i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
 				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
-			i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"", dres[1], dres[0]);
+			i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
+			i += sprintf(TmpTxt+i, "Desc=\"Regression\"\n");
 			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
 			i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
 				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
-			i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"", 
+			i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n", 
 				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
 			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
 			i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
 				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
-			i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"", 
+			i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-%g)^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n", 
 				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
 			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+#endif
 			ts = t * sqrt(dres[7]*((dBounds.Xmax-dres[2])*(dBounds.Xmax-dres[2])/sxx +1.0/(double)n));
 			ty = dBounds.Xmax * dres[0] +dres[1];
 			ly[0] = ty +ts;		ly[1] = ty -ts;
@@ -575,13 +922,13 @@ rep_regression(GraphObj *parent, DataObj *data)
 				if(ly[i] < dBounds.Ymin) dBounds.Ymin = ly[i];
 				if(ly[i] > dBounds.Ymax) dBounds.Ymax = ly[i];
 				}
-			if(txt_obj = mk_scatt(x, y, 0L, 0L, n)){
-				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);
-				}
-			if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x", dres[1],
-				(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
+#ifdef USE_WIN_SECURE
+			if(!bParZ) sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
+			else sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g * x", fabs(dres[0]));
+#else
+			if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
 			else sprintf(TmpTxt, "y = %g * x", fabs(dres[0]));
+#endif
 			if(txt_obj = mk_label((graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
 				graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt)) {
 				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
@@ -597,9 +944,15 @@ rep_regression(GraphObj *parent, DataObj *data)
 			res_tab[1][1] = syy-res_tab[0][1];		res_tab[2][1] = syy;
 			res_tab[0][2] = res_tab[0][1];			res_tab[1][2] = res_tab[1][1]/df;
 			res_tab[0][3] = dres[8];				res_tab[0][4] = dres[9];
-			regr_sum[1][0] = res_tab[0][1]/syy;		regr_sum[0][0] = sqrt(regr_sum[1][0]);
-			mk_table(page, graph->GRect.Xmin, graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0,
-				2, res_tab);
+			dres[12] = res_tab[0][1]/res_tab[2][1];
+			c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
+			c_x = graph->GRect.Xmin;
+			c_y = mk_regr_summary(page, c_x, c_y, dres, ci, n);
+			if(txt_obj = mk_label(c_x, c_y, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>")) {
+				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);						c_y += txtdef1.fSize*1.5;
+				}
+			mk_table(page, c_x, c_y, 2, res_tab);
 			parent->Command(CMD_DROP_GRAPH, page, 0L);
 			}
 		}
@@ -608,6 +961,315 @@ rep_regression(GraphObj *parent, DataObj *data)
 		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
 		free(res_tab);
 		}
-	if(x) free(x);			if(y) free(y);
-	if(rX) delete rX;		if(rY) delete rY;		free(RegrDlg);
+	if(x_desc) free(x_desc);	if(y_desc)free(y_desc);
+	if(x) free(x);				if(y) free(y);
+	if(rX) delete rX;			if(rY) delete rY;		free(RegrDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 2x2 table
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *twDlg_Tmpl =
+	"1,2,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"2,3,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"3,4,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,5,,DEFAULT,PUSHBUTTON,-1,168,10,45,12\n"
+	"5,,,,PUSHBUTTON,2,168,25,45,12\n"
+	"100,101,,,CTEXT,1,35,10,40,8\n"
+	"101,102,,,EDTEXT,0,35,20,40,10\n"
+	"102,103,,,EDTEXT,0,77,20,40,10\n"
+	"103,104,,,EDTEXT,0,35,32,40,10\n"
+	"104,105,,,EDTEXT,0,77,32,40,10\n"
+	"105,106,,,LTEXT,3,10,20,40,8\n"
+	"106,107,,,LTEXT,4,10,32,40,8\n"
+	"107,,,,CTEXT,5,77,10,40,8\n"
+	"400,401,,,EDTEXT,0,119,20,40,10\n"
+	"401,402,,,EDTEXT,0,119,32,40,10\n"
+	"402,403,,,EDTEXT,0,35,44,40,10\n"
+	"403,404,,,EDTEXT,0,77,44,40,10\n"
+	"404,405,,,EDTEXT,0,119,44,40,10\n"
+	"405,406,,,CTEXT,6,119,10,40,8\n"
+	"406,407,,,LTEXT,7,10,44,40,8\n"
+	"407,408,,,LTEXT,2,35,59,40,8\n"
+	"408,409,,,LTEXT,2,35,69,40,8\n"
+	"409,410,,,LTEXT,8,119,59,60,8\n"
+	"410,,,,LTEXT,0,119,69,60,8\n"
+	"600,601,,DEFAULT,PUSHBUTTON,-1,128,10,45,12\n"
+	"601,,,LASTOBJ,PUSHBUTTON,-2,128,25,45,12";
+
+void rep_twowaytable(GraphObj *parent, DataObj *data)
+{
+	DlgInfo *twDlg;
+	void *dyndata[] = {(void*)"Group A", (void*)"Close", (void*)"Case 1", (void*)"Case 2",
+		(void*)"Group B", (void*)"A + B", (void*)"C1+C2", (void*)"Fisher's exact:"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, level, res;
+	int v_idx[] = {101,102,400,103,104,401,402,403,404};
+	double v[9], chi2, p, dn, pf;
+
+	if(!parent || !data) return;
+	if(!(twDlg = CompileDialog(twDlg_Tmpl, dyndata))) return;
+	if(!(Dlg = new DlgRoot(twDlg, data)))return;
+	for(i = 400; i < 405; i++) Dlg->Activate(i, false);
+	level = 0;
+	if (!level) {
+		Dlg->ShowItem(2, false);		Dlg->ShowItem(4, false);	
+		Dlg->ShowItem(5, false);	
+		hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
+		ResizeDlgWnd(hDlg, 370, 150);
+		}
+	else {
+		Dlg->ShowItem(3, false);
+		hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
+		}
+	do {
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch(res) {
+			case 0:
+				res = -1;
+				break;
+			case 600:			//level 0 OK
+				Dlg->ShowItem(2, true);			Dlg->ShowItem(4, true);	
+				Dlg->ShowItem(5, true);			Dlg->ShowItem(3, false);
+				ResizeDlgWnd(hDlg, 450, 200);	Dlg->Command(CMD_REDRAW, 0L, 0L);
+				level = 1;
+			case 4:				//level 1 OK
+				for(i = 0; i < 9; i++) {
+					v[i] = 0.0;					Dlg->GetValue(v_idx[i], &v[i]);
+					v[i] = fabs(floor(v[i]));
+					}
+				v[2] = v[0] + v[1];				v[5] = v[3] + v[4];
+				v[6] = v[0] + v[3];				v[7] = v[1] + v[4];
+				v[8] = v[6] + v[7];				chi2 = v[0]*v[4]-v[1]*v[3];
+				if(v[2] < 32.0 && v[5] < 32.0 && v[6] < 32.0 && v[7] < 32.0) {
+					pf = factrl((int)v[2])/factrl((int)v[0])*factrl((int)v[5])/factrl((int)v[1])
+						*factrl((int)v[6])/factrl((int)v[3])*factrl((int)v[7])/factrl((int)v[4]);
+					pf /= factrl((int)v[8]);
+					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P = %g", pf);
+					Dlg->SetText(410, pf >= 0.001 ? TmpTxt : (char*)"P < 0.001");
+					}
+				else Dlg->SetText(410, "- - -");
+				dn = (v[2]*v[5]*v[6]*v[7]);
+				chi2 = dn > 0.0  ? (chi2*chi2*v[8])/dn : 0.0;
+				p = chi_dist(chi2, 1.0, 1.0);
+				for(i = 0; i < 9; i++) {
+					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "%g", v[i]);
+					Dlg->SetText(v_idx[i], TmpTxt);
+					}
+				dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi2 = %g", chi2);
+				Dlg->SetText(407, TmpTxt);
+				if(p >= 0.001) {
+					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P = %g", p);
+					Dlg->SetText(408, TmpTxt);
+					}
+				else Dlg->SetText(408, "P < 0.001");
+				Dlg->Command(CMD_REDRAW, 0L, 0L);
+				res= -1;
+				break;
+			}
+		}while (res < 0);
+	CloseDlgWnd(hDlg);
+	delete Dlg;		free(twDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// compare means of two groups
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void rep_compmeans(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 42, 10, "Data Input"};
+	double ci = 95.0;
+	DlgInfo *MeanDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"range for first variable",
+		(void*)"range for second variable", (void*)"confidence interval:",
+		(void*)&ci, (void*)" "};
+	char *ttest[] = {"Student's t = %g", "P = %g", "P(corr.) = %g"};
+	char *utest[] = {"Mann-Whitney U = %g", "z = %g", "P = %g", "z(corr.) = %g", "P(corr.) = %g"};
+	char g1_nam[20], g2_nam[20], *c_name;
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, res, n1, n2, r, c, *ny;
+	bool bContinue = false;
+	double *d1, *d2, *rs, dtmp, cx, cy, min1,max1, min2, max2;
+	scaleINFO scale = {{0.0, 0.9}, {0.0, 0.9}, {0.0, 0.9}};
+	char *txt_obj;
+	AccRange *rD;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(MeanDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
+	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+	if(!(Dlg = new DlgRoot(MeanDlg, data)))return;
+	Dlg->ShowItem(107, false);
+	d1 = d2 = 0L;
+	hDlg = CreateDlgWnd("Compare Means", 50, 50, 420, 260, Dlg, 0x0L);
+	do {
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 0:
+			if(bContinue) res = -1;
+			else if(Dlg->GetCheck(10)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+		case 1:
+			if(d1) free(d1);		if(d2) free(d2);		d1 = d2 = 0L;
+			min1 = min2 = dBounds.Ymin = HUGE_VAL;		max1 = max2 = dBounds.Ymax = -HUGE_VAL;
+			if(Dlg->GetText(101,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n1=rD->CountItems())&&(d1=(double*)malloc(n1*sizeof(double)))){
+				if(c_name = rD->RangeDesc(data, 2)) {
+					rlp_strcpy(g1_nam, 20, c_name);		g1_nam[0] = toupper(g1_nam[0]);
+					free(c_name);
+					}
+				else rlp_strcpy(g1_nam, 20, "Group 1");
+				for(n1 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+					if(data->GetValue(r, c, &dtmp)){
+						if(dBounds.Ymin > dtmp) dBounds.Ymin = dtmp;
+						if(dBounds.Ymax < dtmp) dBounds.Ymax = dtmp;
+						if(min1 > dtmp) min1 = dtmp;		if(max1 < dtmp) max1 = dtmp;
+						d1[n1++] = dtmp;
+						}
+					}
+				delete rD;
+				}
+			if(Dlg->GetText(103,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n2=rD->CountItems())&&(d2=(double*)malloc(n1*sizeof(double)))){
+				if(c_name = rD->RangeDesc(data, 2)) {
+					rlp_strcpy(g2_nam, 20, c_name);		g2_nam[0] = toupper(g2_nam[0]);
+					free(c_name);
+					}
+				else rlp_strcpy(g2_nam, 20, "Group 2");
+				for(n2 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+					if(data->GetValue(r, c, &dtmp)){
+						if(dBounds.Ymin > dtmp) dBounds.Ymin = dtmp;
+						if(dBounds.Ymax < dtmp) dBounds.Ymax = dtmp;
+						if(min2 > dtmp) min2 = dtmp;		if(max2 < dtmp) max2 = dtmp;
+						d2[n2++] = dtmp;
+						}
+					}
+				delete rD;
+				}
+			if(!d1 || !d2 || n1 < 2 || n2 < 2) {
+				InfoBox("Insufficient data to calculate means!");
+				bContinue = true;
+				res = -1;
+				}
+			Dlg->GetValue(105, &ci);
+			break;
+			}
+		}while (res < 0);
+	if(res == 1 && d1 && d2 && n1>1 && n2>1 && (rs = (double*)malloc(40*sizeof(double))) && (ny = (int*)malloc(2*sizeof(int)))) {
+		dBounds.Xmin = 0.5;		rs[0] = 1.0;		dBounds.Xmax = 2.3;		rs[1] = 2.0;
+		dtmp = d_variance(n1, d1, &rs[2], 0L);		rs[10] = sqrt(dtmp);
+		dtmp = d_variance(n2, d2, &rs[3], 0L);		rs[11] = sqrt(dtmp);
+		rs[12] = (double)n1;						rs[13] = (double)n2;
+		rs[6] = rs[10]/sqrt(rs[12]);				rs[7] = rs[11]/sqrt(rs[13]);
+		rs[4] = rs[2] - rs[6];						rs[5] = rs[3] - rs[7];
+		rs[6] += rs[2];								rs[7] += rs[3];
+		rs[8] = rs[2] - rs[10];						rs[9] = rs[3] - rs[11];
+		rs[10] += rs[2];							rs[11] += rs[3];
+		ny[0] = n1;									ny[1] = n2;
+		rep_init();									page = new Page(parent, data);
+		ci /= 100.0;
+		mk_header(page, "<b>Compare Means of Two Groups</b>");
+		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_boxplot(rs, rs+2, rs+4, rs+6, rs+8, rs+10,
+				ny, 2,"Mean","Std. Err.","Std. Dev."))){
+			scale.sx.fx = (txtdef1.fSize*5.0);			scale.sy.fx = (txtdef1.fSize*10.0);
+			graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
+			graph->DRect.Xmin *= 0.8;					graph->moveable = 0;
+			graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);								graph->Command(CMD_SCALE, &scale, 0L);
+			cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0;
+			cy = mk_mean_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, ci, g1_nam);
+			cy = mk_mean_report(page, cx, cy + txtdef1.fSize, d2, n2, ci, g2_nam);
+			cy += linsp1;
+			if(txt_obj = mk_label(graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, 
+				&txtdef1, "<b>t-Test:</b>")) {
+				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);								cy += linsp1;
+				}
+			d_ttest(d1, d2, n1, n2, 0L, 0L, rs+15);
+			for(i = 0; i < 3; i++) {
+				switch(i) {
+					case 0:
+						dtmp = rs[24];			break;
+					case 1:
+						dtmp = rs[21];			break;
+					case 2:
+						dtmp = rs[23];			break;
+					}
+#ifdef USE_WIN_SECURE
+				j = sprintf_s(TmpTxt, 80, ttest[i], dtmp);
+#else
+				j = sprintf(TmpTxt, ttest[i], dtmp);
+#endif
+				if(i && dtmp < 0.0001) {
+					while(TmpTxt[j] != '=' && j) j--;
+					rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
+					}
+				if(txt_obj = mk_label(cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt)) {
+					OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+					free(txt_obj);							cy += linsp1/1.2;
+					}
+				}
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		d_quartile(n1, d1, &rs[6], &rs[2], &rs[4]);
+		d_quartile(n2, d2, &rs[7], &rs[3], &rs[5]);
+		rs[8] = min1;	rs[9] = min2;	rs[10] = max1;	rs[11] = max2;
+		cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
+		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_boxplot(rs, rs+2, rs+4, rs+6, rs+8, rs+10,
+				ny, 2,"Median","25-75%","Min./Max."))){
+			scale.sy.fx = cy;
+			graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
+			graph->DRect.Xmin *= 0.8;					graph->moveable = 0;
+			graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);								graph->Command(CMD_SCALE, &scale, 0L);
+			cy = mk_median_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, .95, g1_nam);
+			cy = mk_median_report(page, cx, cy + txtdef1.fSize, d2, n2, .95, g2_nam);
+			cy += linsp1;
+			if(txt_obj = mk_label(graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, 
+				&txtdef1, "<b>u-Test:</b>")) {
+				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);								cy += linsp1;
+				}
+			d_utest(d1, d2, n1, n2, 0L, 0L, rs+15);
+			for(i = 0; i < 5; i++) {
+				switch(i) {
+					case 0:
+						dtmp = rs[17];			break;
+					case 1:
+						dtmp = rs[18];			break;
+					case 2:
+						dtmp = rs[21];			break;
+					case 3:
+						dtmp = rs[22];			break;
+					case 4:
+						dtmp = rs[23];			break;
+					}
+#ifdef USE_WIN_SECURE
+				j = sprintf_s(TmpTxt, 80, utest[i], dtmp);
+#else
+				j = sprintf(TmpTxt, utest[i], dtmp);
+#endif
+				if(i && dtmp < 0.0001) {
+					while(TmpTxt[j] != '=' && j) j--;
+					rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
+					}
+				if(txt_obj = mk_label(cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt)) {
+					OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+					free(txt_obj);							cy += linsp1/1.2;
+					}
+				}
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		parent->Command(CMD_DROP_GRAPH, page, 0L);	free(rs);
+		}
+	CloseDlgWnd(hDlg);		delete Dlg;
+	free(MeanDlg);			if(d1) free(d1);	if(d2) free(d2);
 }
diff --git a/rlp_math.cpp b/rlp_math.cpp
index e8d2aac..0f6d86f 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -635,7 +635,17 @@ double lognorm_freq(double x, double m, double s)
 //chi square distribution
 double chi_dist(double x, double df, double)
 {
-	return gammq(df/2.0, x/2);
+	return gammq(df/2.0, x/2.0);
+}
+
+double chi_freq(double x, double df)
+{
+	if(x < 0.0 || df <= 0.0) return 0.0;
+	if(x < 1.0e-32) x = 1.0e-32;
+//formula by Wikipedia 
+//	return exp(log(2.0)*(1.0-df/2.0)+log(x)*(df-1.0)+x*x/-2.0-gammln(df/2.0));
+//formula by StatSoft's STATISTICA documentation
+	return exp(-x/2.0+log(x)*(df/2.0-1.0)-log(2.0)*df/2.0-gammln(df/2.0));
 }
 
 //t-distribution
@@ -644,6 +654,15 @@ double t_dist(double t, double df, double)
 	return betai(df/2.0, 0.5, (df/(df+t*t)));
 }
 
+double t_freq(double t, double df)
+{
+	double a, b, c, d;
+ 
+	a = gammln((df+1.0)/2.0);		b = log(sqrt(df * _PI));
+	c = gammln(df/2.0);				d = log(1.0+t*t/df) * (df+1)/2.0;
+	return exp(a-b-c-d);
+}
+
 //poisson distribution
 double pois_dist(double x, double m, double)
 {
@@ -656,13 +675,18 @@ double f_dist(double f, double df1, double df2)
 	return betai(df2/2.0, df1/2.0, df2/(df2+df1*f));
 }
 
+double f_freq(double x, double df1, double df2)
+{
+	double a, b, c, d;
+
+	a = gammln((df1+df2)/2.0);		b = gammln(df1/2.0) + gammln(df2/2.0);
+	c = log(df1/df2) * df1/2.0 + log(x) * (df1/2.0-1.0);
+	d = log(1+(df1/df2)*x) * (-(df1+df2)/2.0);
+	return exp(a-b+c+d);
+}
+
 //---------------------------------------------------------------------------
 // Inverse of statitistical functions:
-//    Use a combination of the Newton-Raphson method and bisection
-// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
-//    Numerical Rcipies in C. The Art of Scientific Computing, 
-//    Cambridge University Press, ISBN 0-521-35465, pp. 273 ff.
-
 // funcd supplies the function value fn and the derivative df of the function sf at x
 void funcd(double x, double *fn, double *df, double (*sf)(double, double, double), 
 		   double df1, double df2, double p)
@@ -671,6 +695,10 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 
 	*fn = (sf)(x, df1, df2);
 	if(sf == norm_dist) *df = norm_freq(x, df1,df2);
+	else if(sf == chi_dist) *df = -chi_freq(x, df1);
+	else if(sf == t_dist) *df = -2.0 * t_freq(x, df1);
+	else if(sf == f_dist) *df = -1.0 * f_freq(x, df1, df2);
+//	if(true){
 	else {
 		y1 = (sf)(x * 0.995, df1, df2);
 		y2 = (sf)(x * 1.005, df1, df2);
@@ -679,50 +707,23 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 	*fn = *fn - p;
 }
 
-//distinv does actual bisection and Newton-Raphson root finding
+//distinv does actual Newton-Raphson root finding
 double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0)
 {
-	int j = 0;
-	double df, dx, dxold, f, fh, fl;
-	double swap, temp, xh, xl, rts; 
-	double x1 = x0/2.0, x2 = x0+x1;
-
-	do {
-		funcd(x1, &fl, &df, sf, df1, df2, p);
-		funcd(x2, &fh, &df, sf, df1, df2, p);
-		if(++j > 200) return 0.0;
-		if(fl*fh < 0.0) break;
-		dx = fabs(x2-x1);
-		x1 = (x1 > dx) ? x1-dx : x1/2.0;			x2 += dx;
-		}while(fl*fh >= 0.0);
-	if(fl <= 0.0) {
-		xl = x1;		xh = x2;
-		}
-	else {
-		xh = x1;		xl = x2;
-		swap = fl;		fl = fh;	fh = swap;
-		}
-	rts = x0;	dxold = fabs(x2-x1);	dx = dxold;
-	funcd(rts, &f, &df, sf, df1, df2, p);
-	for(j = 1; j <= 500; j++) {
-        if((((rts-xh)*df-f)*((rts-xl)*df-f) >= 0.0) || (fabs(2.0*f) > fabs(dxold * df))) {
-			dxold = dx;		dx = 0.5 * (xh-xl);		rts = xl + dx;
-			if(xl == rts) return rts;
-			}
-		else {
-			dxold = dx;		dx = f/df;		temp = rts;		rts -= dx;
-			if(temp == rts) return rts;
-			}
-		if(fabs(dx) < _PREC) return rts;
-		funcd(rts, &f, &df, sf, df1, df2, p);
-		if(f < 0.0) {
-			xl = rts;	fl = f;
-			}
-		else {
-			xh = rts;	fh = f;
+	int i, j;
+	double df, dx, f, rtn;
+
+	for(j = 0, rtn = dx = x0; j < 100; j++) {
+		for( i= 0; i < 100; i++) {
+			funcd(rtn, &f, &df, sf, df1, df2, p);
+			if(fabs(df) > 1.0e-12) break;
+			rtn += (dx = dx/2.0);
+			if(i >= 99) return HUGE_VAL;
 			}
+		dx = f/df*(0.01*(double)(100-j));					rtn -= dx;
+		if(fabs(dx) < _PREC && j > 3) return rtn; 
 		}
-	return rts;
+	return rtn;
 }
 
 //---------------------------------------------------------------------------
@@ -841,9 +842,16 @@ double d_skew(int n, double *v)
 {
 	double sum, avg, sd, tmp, dn = n;
 	int i;
-
-	for(i = 0, sum = 0.0; i < n; i++) sum += v[i];
-	for(i = 0, avg = sum/dn, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
+//	double x, skew;
+
+//	sd = sqrt(d_variance(n, v, &avg, 0L));
+//	for(i = 0, skew = 0.0; i < n; i++){
+//		x = (v[i]-avg)/sd;
+//		skew += (x*x*x - skew)/((double)(i+1));
+//		}
+//	return skew;
+	for(i = 0, avg = 0.0; i < n; i++) avg += ((v[i]-avg)/((double)(i+1)));
+	for(i = 0, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
 	for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp);
 	return sum * dn/((dn-1.0)*(dn-2.0));
 }
@@ -950,13 +958,10 @@ void crank(int n, double *w0, double *s)
 			w[j] = j;		++j;
 			}
 		else {
-			for(jt = j+1; jt <= n; jt++)
-				if(w[jt] != w[j]) break;
+			for(jt = j+1; jt <= n; jt++) if(w[jt] != w[j]) break;
 			rank = 0.5 * (j+jt-1);
 			for(ji = j; ji <= (jt-1); ji++) w[ji] = rank;
-			t = jt -j;
-			*s += t*t*t -t;
-			j = jt;
+			t = jt -j;		*s += t*t*t -t;				j = jt;
 			}
 		}
 	if(j == n) w[n] = n;
@@ -1093,10 +1098,10 @@ double d_covar(double *x, double *y, int n, char *dest, DataObj *data)
 }
 
 //Mann-Whitney U Test
-double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results)
 {
-	double *da, *ta, u1, u2, su, tmp;
-	double res[7];
+	double *da, *ta, u1, u2, su, su1, ts, dn1 = n1, dn2 = n2;
+	double res[9];
 	AccRange *rD;
 	int i, j, n, r, c;
 
@@ -1112,29 +1117,35 @@ double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 	for(j = 0; j < n2; j++) {
 		da[i] = y[j];		ta[i++] = 2.0;
 		}
-	SortArray2(n, da, ta);	crank(n, da, &tmp);
+	SortArray2(n, da, ta);	crank(n, da, &ts);
 	for(i = 0, res[0] = res[1] = 0.0; i < n; i++) {
 		if(ta[i] == 1.0) res[0] += da[i];
 		else res[1] += da[i];
 		}
-	free(da);									free(ta);
-	u1 = (n1*n2 + (n1*(n1+1))/2.0) - res[0];	u2 = (n1*n2 + ((n2+1)*n2)/2.0) - res[1];
-	su = sqrt((n1*n2*(n1+n2+1))/12.0);			res[2] = u2 > u1 ? u2 : u1;
+	free(da);										free(ta);
+	u1 = (dn1*dn2 + (dn1*(dn1+1))/2.0) - res[0];	u2 = (dn1*dn2 + ((dn2+1)*dn2)/2.0) - res[1];
+	su = sqrt((dn1*dn2*(dn1+dn2+1))/12.0);			res[2] = u2 > u1 ? u2 : u1;
+	su1 = ((dn1*dn2)/((dn1+dn2)*(dn1+dn2-1))) * (((dn1+dn2)*(dn1+dn2)*(dn1+dn2)-(dn1+dn2)-ts)/12.0);
+	su1 = sqrt(su1);
 	res[3] = (res[2] - (n1*n2)/2.0)/su;			res[6] = errfc(res[3]/_SQRT2);
+	res[4] = n1;								res[5] = n2;
+	res[7] = (res[2] - (n1*n2)/2.0)/su1;		res[8] = errfc(res[7]/_SQRT2);
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		res[4] = n1;							res[5] = n2;
 		rD->GetFirst(&c, &r);
-		for(i = 0; i < 7 && rD->GetNext(&c, &r); i++) {
+		for(i = 0; i < 9 && rD->GetNext(&c, &r); i++) {
 			data->SetValue(r, c, res[i]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
-	return res[6];
+	else if(results) {
+		for(i = 0; i < 9; i++) results[i] = res[i];
+		}
+	return res[8];
 }
 
 //t-test
-double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
+double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results)
 {
 	int i, r, c;
 	double sx, sy, mx, my, d, df, p;
@@ -1148,7 +1159,7 @@ double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 	//Welch's correction for differences in variance
 	df = (sx/(double)n1)*(sx/(double)n1)/(double)(n1+1)+(sy/(double)n2)*(sy/(double)n2)/(double)(n2+1);
 	df = (sx/(double)n1+sy/(double)n2)*(sx/(double)n1+sy/(double)n2)/df;
-	df -= 2.0;
+	df -= 2.0;		df = floor(df);
 
 //	an alternative formula for correction
 //	p = (sx/(double)n1)*(sx/(double)n1)/(double)(n1-1) + (sy/(double)n2)*(sy/(double)n2)/(double)(n2-1);
@@ -1167,6 +1178,12 @@ double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	else if(results) {
+		results[0] = mx;	results[1] = sqrt(sx/(double)(n1-1));	results[2] = n1;
+		results[3] = my;	results[4] = sqrt(sy/(double)(n2-1));	results[5] = n2;
+		results[7] = df;	df = (n1-1) + (n2-1);	results[6] = betai(df/2.0, 0.5, (df/(df+d*d)));
+		results[8] = p;		results[9] = d;
+		}
 	return p;
 }
 
@@ -1299,7 +1316,11 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 		switch (fmt[i]) {
 		case 'Y':		case 'y':			// year is numeric
 			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%d", &dt->year)) {
+#else
 			if(sscanf(src+j, "%d", &dt->year)) {
+#endif
 				if(dt->year < 0) return 0;
 				while(isdigit(src[j])) j++;
 				if(dt->year<60) dt->year += 2000;
@@ -1323,7 +1344,11 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 			break;
 		case 'V':		case 'v':			//    or numeric
 			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%d", &dt->month)) {
+#else
 			if(sscanf(src+j, "%d", &dt->month)) {
+#endif
 				if(dt->month <= 0 || dt->month > 12) return 0;
 				j++;				if(isdigit(src[j])) j++;
 				}
@@ -1331,14 +1356,22 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 			break;
 		case 'Z':		case 'z':			// day of month is numeric
 			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%d", &dt->dom)) {
+#else
 			if(sscanf(src+j, "%d", &dt->dom)) {
+#endif
 				if(dt->dom <= 0 || dt->dom > 31) return 0;
 				j++;				if(isdigit(src[j])) j++;
 				}
 			else return 0;
 			break;
 		case 'H':		case 'h':			// hours are numeric
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%2d", &dt->hours)) {
+#else
 			if(sscanf(src+j, "%2d", &dt->hours)) {
+#endif
 				if(dt->hours < 0 || dt->hours > 23) return 0;
 				j++;				if(isdigit(src[j])) j++;
 				}
@@ -1346,7 +1379,11 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 			break;
 		case 'M':		case 'm':			// minutes are numeric
 			if(j && src[j] == ' ' || src[j] == ':') j++;
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%2d", &dt->minutes)) {
+#else
 			if(sscanf(src+j, "%2d", &dt->minutes)) {
+#endif
 				if(dt->minutes < 0 || dt->minutes >= 60) return 0;
 				j++;				if(isdigit(src[j])) j++;
 				}
@@ -1355,7 +1392,11 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 		case 'S':		case 's':			// seconds are numeric
 		case 'T':		case 't':
 			if(j && src[j] == ' ' || src[j] == ':') j++;
+#ifdef USE_WIN_SECURE
+			if(sscanf_s(src+j, "%lf", &dt->seconds)) {
+#else
 			if(sscanf(src+j, "%lf", &dt->seconds)) {
+#endif
 				if(dt->seconds < 0.0 || dt->seconds >= 60.0) return 0;
 				while(isdigit(src[j]) || src[j] == '.') j++;
 				}
@@ -1390,6 +1431,78 @@ static char *date2text(rlp_datetime *dt, char *fmt)
 	secs = dt->seconds;
 	if (secs > 59.4999) secs = 59.4999;
 	for(pos = i = 0; fmt[i] && pos < 70; i++) {
+#ifdef USE_WIN_SECURE
+		switch(fmt[i]) {
+		case 'Y':
+			if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%4d", dt->year);
+			else pos += sprintf_s(res+pos, 80-pos, "####");			break;
+		case 'y':
+			if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%02d", (dt->year %100));
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'Z':
+			if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dom);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'z':
+			if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dom);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'X':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_month[dt->month-1]);
+			else pos += sprintf_s(res+pos, 80-pos, "###");			break;
+		case 'x':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_months[dt->month-1]);
+			else pos += sprintf_s(res+pos, 80-pos, "###");			break;
+		case 'V':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->month);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'v':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->month);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'W':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_month[dt->month-1][0]);
+			else pos += sprintf_s(res+pos, 80-pos, "#");			break;
+		case 'D':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_day[dt->dow-1]);
+			else pos += sprintf_s(res+pos, 80-pos, "###");			break;
+		case 'd':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_days[dt->dow-1]);
+			else pos += sprintf_s(res+pos, 80-pos, "###");			break;
+		case 'E':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dow);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'e':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dow);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'F':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_day[dt->dow-1][0]);
+			else pos += sprintf_s(res+pos, 80-pos, "#");			break;
+		case 'H':
+			if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->hours);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'h':
+			if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->hours);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'M':
+			if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->minutes);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'm':
+			if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->minutes);
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'S':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02d", iround(secs));
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 's':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%d", iround(secs));
+			else pos += sprintf_s(res+pos, 80-pos, "##");			break;
+		case 'T':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02.2lf", dt->seconds);
+			else pos += sprintf_s(res+pos, 80-pos, "##.##");		break;
+		case 't':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%.2lf", dt->seconds);
+			else pos += sprintf_s(res+pos, 80-pos, "##.##");		break;
+		default:
+			pos += sprintf_s(res+pos, 80-pos, "%c", fmt[i]);		break;
+			}
+#else
 		switch(fmt[i]) {
 		case 'Y':
 			if(dt->year) pos+=sprintf(res+pos, "%4d", dt->year);
@@ -1460,7 +1573,8 @@ static char *date2text(rlp_datetime *dt, char *fmt)
 		default:
 			pos += sprintf(res+pos, "%c", fmt[i]);		break;
 			}
-		}
+#endif
+	}
 	res[pos] = 0;
 	return res;
 }
@@ -1554,8 +1668,14 @@ double now_today()
 {
 	double res = 0.0;
 	time_t ti = time(0L);
+#ifdef USE_WIN_SECURE
+	char dtbuff[80];
 
+	ctime_s(dtbuff, 80, &ti);
+	date_value(dtbuff+4, "x z H:M:S Y", &res);
+#else
 	date_value(ctime(&ti)+4, "x z H:M:S Y", &res);
+#endif
 	return res;
 }
 
@@ -1574,158 +1694,6 @@ void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h
 //---------------------------------------------------------------------------
 // Use the Delauney triangulation to create a 3D mesh of dispersed data
 //
-class Triangle {
-public:
-	Triangle *next;
-	fPOINT3D pt[4];
-
-	void SetRect();
-	bool TestVertex(double x, double y);
-
-private:
-	double cx, cy, r2;				//circumcircle
-	fRECT rc;						//bounding rectangle
-	lfPOINT ld[3];					//line eqations
-};
-
-class Triangulate {
-public:
-	Triangle *trl;
-
-	Triangulate(Triangle *t_list);
-	bool AddEdge(fPOINT3D *p1, fPOINT3D *p2);
-	bool AddVertex(fPOINT3D *v);
-
-private:
-	typedef struct edge {
-		edge *next;
-		fPOINT3D p1, p2;
-	};
-	edge *edges;
-};
-
-void
-Triangle::SetRect()
-{
-	int i, i2;
-	double dy1, dy2, dx, dy;
-	double m1, m2, mx1, mx2, my1, my2;
-
-	//setup bounding rectangle
-	rc.Xmin = rc.Xmax = pt[0].fx;	rc.Ymin = rc.Ymax = pt[0].fy;
-	for(i = 1; i < 3; i++) {
-		if(pt[i].fx < rc.Xmin) rc.Xmin = pt[i].fx;
-		if(pt[i].fx > rc.Xmax) rc.Xmax = pt[i].fx;
-		if(pt[i].fy < rc.Ymin) rc.Ymin = pt[i].fy;
-		if(pt[i].fy > rc.Ymax) rc.Ymax = pt[i].fy;
-		}
-	//get three line equations in 2D
-	for(i = 0; i < 3; i++) {
-		i2 = (i+1)%3;
-		ld[i].fx = pt[i].fy;
-		if(pt[i].fx != pt[i2].fx) {
-			ld[i].fy = (pt[i2].fy - pt[i].fy) / (pt[i2].fx - pt[i].fx);
-			}
-		else ld[i].fy = HUGE_VAL;
-		}
-	//close polygon
-	pt[3].fx = pt[0].fx;	pt[3].fy = pt[0].fy;	pt[3].fz = pt[0].fz;
-	//circumcricle
-	dy1 = fabs(pt[0].fy - pt[1].fy);			dy2 = fabs(pt[1].fy - pt[2].fy);
-	m1 = (pt[0].fx - pt[1].fx)/(pt[1].fy - pt[0].fy);
-	m2 = (pt[1].fx - pt[2].fx)/(pt[2].fy - pt[1].fy);
-	mx1 = (pt[0].fx + pt[1].fx)/2.0;			my1 = (pt[0].fy + pt[1].fy)/2.0;
-	mx2 = (pt[1].fx + pt[2].fx)/2.0;			my2 = (pt[1].fy + pt[2].fy)/2.0;
-	if(dy1 < 1.0e-16 && dy2 < 1.0e-16) {
-		cy = (pt[0].fy + pt[1].fy + pt[2].fy)/3.0;
-		cx = (pt[0].fx + pt[1].fx + pt[2].fx)/3.0;
-		r2 = 0.0;			return;
-		}
-	else if(dy1 < 1.0e-16) {
-		cx = (pt[0].fx + pt[1].fx)/2.0;			cy = m2 * (cx - mx2) + my2;
-		}
-	else if(dy2 < 1.0e-16) {
-		cx = (pt[2].fx + pt[1].fx)/2.0;			cy = m1 * (cx - mx1) + my1;
-		}
-	else {
-		cx = (m1*mx1-m2*mx2+my2-my1)/(m1-m2);	cy = m1*(cx - mx1) + my1;
-		}
-	dx = pt[1].fx - cx;	dy = pt[1].fy - cy;		r2 = dx * dx + dy * dy;
-}
-
-bool
-Triangle::TestVertex(double x, double y)
-{
-	double dx, dy;
-
-	dx = x-cx;		dx = dx * dx;		dy = y-cy;		dy = dy * dy;
-	return (dx+dy)<r2;
-}
-
-Triangulate::Triangulate(Triangle *t_list)
-{
-	trl = t_list;		edges = 0L;
-}
-
-bool
-Triangulate::AddEdge(fPOINT3D *p1, fPOINT3D *p2)
-{
-	edge *ce, *ne;
-
-	//if edge exists delete both the new and the existing edge
-	for(ce = edges, ne = 0L; (ce); ) {
-		if((ce->p1.fx == p1->fx && ce->p1.fy == p1->fy && ce->p1.fz == p1->fz
-			&& ce->p2.fx == p2->fx && ce->p2.fy == p2->fy && ce->p2.fz == p2->fz)
-			|| (ce->p2.fx == p1->fx && ce->p2.fy == p1->fy && ce->p2.fz == p1->fz
-			&& ce->p1.fx == p2->fx && ce->p1.fy == p2->fy && ce->p1.fz == p2->fz)) {
-			if(ne) ne->next = ce->next;
-			else edges = ce->next;
-			delete ce;					return true;
-			}
-		ne = ce;	ce = ce->next;
-		}
-	//come here for new edge
-	if(ne = new edge()) {
-		ne->p1.fx = p1->fx;		ne->p1.fy = p1->fy;		ne->p1.fz = p1->fz;
-		ne->p2.fx = p2->fx;		ne->p2.fy = p2->fy;		ne->p2.fz = p2->fz;
-		ne->next = edges;		edges = ne;
-		}
-	return false;
-}
-
-bool
-Triangulate::AddVertex(fPOINT3D *v)
-{
-	Triangle *trc, *trn, *tr1;
-	edge *ce, *ae;
-
-	for(trc = trl, trn = 0L, edges = 0L; (trc);) {
-		tr1 = trc->next;
-		//delete triangles whose circumcircle enclose the new vertex
-		if(trc->TestVertex(v->fx, v->fy)) {
-			AddEdge(&trc->pt[0], &trc->pt[1]);		AddEdge(&trc->pt[1], &trc->pt[2]);
-			AddEdge(&trc->pt[0], &trc->pt[2]);
-			if(trn) trn->next = trc->next;
-			else trl = trc->next;
-			if(trl == trc) trl = 0L;	
-			delete trc;
-			}
-		else trn = trc;
-		trc = tr1;
-		}
-	//create new triangles from those edges which where found only once
-	for(ce = edges; (ce); ) {
-		if(trn = new Triangle()) {
-			trn->pt[0].fx = ce->p1.fx;	trn->pt[0].fy = ce->p1.fy;	trn->pt[0].fz = ce->p1.fz;
-			trn->pt[1].fx = ce->p2.fx;	trn->pt[1].fy = ce->p2.fy;	trn->pt[1].fz = ce->p2.fz;
-			trn->pt[2].fx = v->fx;		trn->pt[2].fy = v->fy;		trn->pt[2].fz = v->fz;
-			trn->SetRect();				trn->next = trl;			trl = trn;
-			ae = ce->next;				delete(ce);					ce = ae;
-			}
-		}
-	return true;
-}
-
 Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data)
 {
 	AccRange *rX, *rY, *rZ;
diff --git a/rlplot.cpp b/rlplot.cpp
index 6e58fb9..5084b18 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -1,5118 +1,5242 @@
-//RLPlot.cpp, Copyright 2000-2006 R.Lackner
-//
-//    This file is part of RLPlot.
-//
-//    RLPlot 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.
-//
-//    RLPlot 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 RLPlot; if not, write to the Free Software
-//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-//
-#include "rlplot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-
-extern tag_Units Units[];
-extern char TmpTxt[];
-extern Default defs;
-
-GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
-Label *CurrLabel = 0L;
-Graph *CurrGraph = 0L;
-Axis **CurrAxes = 0L;
+//RLPlot.cpp, Copyright 2000-2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot 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.
+//
+//    RLPlot 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 RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+extern tag_Units Units[];
+extern char TmpTxt[];
+extern Default defs;
+
+GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
+Label *CurrLabel = 0L;
+Graph *CurrGraph = 0L;
+Axis **CurrAxes = 0L;
 dragHandle *CurrHandle = 0L;
-UndoObj Undo;
-int cGraphs = 0;
-int cPlots = 0;
-int cPages = 0;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// grapic objects
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-GraphObj::GraphObj(GraphObj *par, DataObj *d)
-{
-	parent = par;	data = d;	Id = GO_UNKNOWN;
-	type = moveable = 0;		name = 0L;
-	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
-}
-
-GraphObj::~GraphObj()
-{
-	if(name)free(name);
-	name = 0L;
-	if(CurrGO == this)	CurrGO = 0L;
-	if(TrackGO == this) TrackGO = 0L;
-}
-
-double
-GraphObj::GetSize(int select)
-{
-	if(parent) return parent->GetSize(select);
-	else return defs.GetSize(select);
-}
-
-DWORD 
-GraphObj::GetColor(int select){
-	return defs.Color(select);
-}
+UndoObj Undo;
+int cGraphs = 0;
+int cPlots = 0;
+int cPages = 0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// grapic objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+GraphObj::GraphObj(GraphObj *par, DataObj *d)
+{
+	parent = par;	data = d;	Id = GO_UNKNOWN;
+	type = moveable = 0;		name = 0L;
+	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
+}
+
+GraphObj::~GraphObj()
+{
+	if(name)free(name);		name = 0L;
+	if(CurrGO == this)		CurrGO = 0L;
+	if(TrackGO == this)	 TrackGO = 0L;
+}
+
+double
+GraphObj::GetSize(int select)
+{
+	if(parent) return parent->GetSize(select);
+	else return defs.GetSize(select);
+}
+
+DWORD 
+GraphObj::GetColor(int select){
+	return defs.Color(select);
+}
 
 void
 GraphObj::RegGO(void *n)
 {
 	((notary*)n)->AddRegGO(this);
 }
-
-void *
-GraphObj::ObjThere(int x, int y)
-{
-	if(IsInRect(&rDims, x, y)) return this;
-	else return 0L;
-}
-
-void
-GraphObj::Track(POINT *p, anyOutput *o)
-{
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// This is a special object to read certain svg-settings from a *.rlp file
-svgOptions::svgOptions(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(defs.svgScript) free(defs.svgScript);
-	if(defs.svgAttr) free(defs.svgAttr);
-	defs.svgScript = defs.svgAttr = 0L;
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		if(script) defs.svgScript = script;
-		if(svgattr) defs.svgAttr = svgattr;
-		script = svgattr = 0L;
-		}
-	Id=GO_SVGOPTIONS;
-}
-
-svgOptions::~svgOptions()
-{
-	if(script)free(script);
-	script = 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Symbols are graphic objects
-Symbol::Symbol(GraphObj *par, DataObj *d, double x, double y, int which,
-		int xc, int xr, int yc, int yr):GraphObj(par, d)
-{
-	//Symbols with no parent are part of a dialog
-	FileIO(INIT_VARS);
-	fPos.fx = x;
-	fPos.fy = y;
-	type = which;
-	Id = GO_SYMBOL;
-	if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			cssRef = 2;
-			}
-		}
-}
-
-Symbol::Symbol(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		SymFill.hatch = (LineDEF *) NULL;
-		}
-}
-
-Symbol::~Symbol()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-double
-Symbol::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_MINE:
-	case SIZE_SYMBOL:
-		return size;
-	case SIZE_SYM_LINE:
-		return SymLine.width;
-	case SIZE_XPOS:
-		return fPos.fx;
-	case SIZE_YPOS:
-		return fPos.fy;
-	default:
-		return parent ? parent->GetSize(select) : defs.GetSize(select);
-		}
-}
-
-bool
-Symbol::SetSize(int select, double value)
-{
-	switch(select & 0xfff){
-	case SIZE_MINE:
-	case SIZE_SYMBOL:
-		size = value;
-		return true;
-	case SIZE_SYM_LINE:
-		SymLine.width = value;
-		return true;
-	case SIZE_XPOS:
-		fPos.fx = value;
-		return true;
-	case SIZE_YPOS:
-		fPos.fy = value;
-		return true;
-	}
-	return false;
-}
-
-DWORD
-Symbol::GetColor(int select)
-{
-	switch(select) {
-	case COL_SYM_LINE:
-		return SymLine.color;
-	case COL_SYM_FILL:
-		return SymFill.color;
-	default:
-		return parent ? parent->GetColor(select) : defs.Color(select);
-		}
-}
-
-bool
-Symbol::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_SYM_LINE:
-		SymLine.color = col;
-		if(SymTxt) SymTxt->ColTxt = col;
-		return true;
-	case COL_SYM_FILL:
-		SymFill.color = col;
-		return true;
-	default:
-		return false;
-		}
-}
-
-void
-Symbol::DoPlot(anyOutput *target)
-{
-	int ix, iy, rx, ry, atype;
-	lfPOINT fip;
-	POINT pts[5];
-	FillDEF cf;
-
-	if(size <= 0.001) return;
-	atype = (type  & 0xfff);
-	memcpy(&cf, &SymFill, sizeof(FillDEF));
-	if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
-		atype == SYM_TRIADF || atype == SYM_DIAMONDF) cf.color = SymLine.color;
-	if(type & SYM_POS_PARENT) {
-		if(!parent) return;
-		fip.fx = parent->GetSize(SIZE_XCENTER);
-		fip.fy = parent->GetSize(SIZE_YCENTER);
-		}
-	else if(!target->fp2fip(&fPos, &fip)) return;
-	ix = iround(fip.fx);		iy = iround(fip.fy);
-	target->SetLine(&SymLine);
-	switch(atype){
-	default:
-	case SYM_CIRCLE:		//circle
-	case SYM_CIRCLEF:		//filled circle
-		rx = target->un2ix(size/2.0);		ry = target->un2iy(size/2.0); 
-		target->SetFill(&cf);
-		target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
-		rx--;ry--;			//smaller marking rectangle
-		break;
-	case SYM_RECT:			//rectange (square)
-	case SYM_RECTF:			//filled rectangle
-		rx = target->un2ix(size/2.25676);
-		ry = target->un2iy(size/2.25676);
-		target->SetFill(&cf);
-		target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
-		break;
-	case SYM_TRIAU:			//triangles up and down, open or closed
-	case SYM_TRIAUF:	case SYM_TRIAD:		case SYM_TRIADF:
-		rx = target->un2ix(size/1.48503);
-		ry = target->un2iy(size/1.48503);
-		target->SetFill(&cf);
-		pts[0].x = pts[3].x = ix - rx;		pts[1].x = ix;		pts[2].x = ix+rx;
-		if(atype == SYM_TRIAU || atype == SYM_TRIAUF) {		//patch by anonymous
-			pts[0].y = pts[2].y = pts[3].y = iy+target->un2iy(size*0.38878f);
-			pts[1].y = iy-target->un2iy(size*0.77756f);
-			}
-		else {
-			pts[0].y = pts[2].y = pts[3].y = iy-target->un2iy(size*0.38878f);
-			pts[1].y = iy+target->un2iy(size*0.77756f);
-			}
-		target->oPolygon(pts, 4);
-		rx--; ry--;
-		break;
-	case SYM_DIAMOND:	case SYM_DIAMONDF:
-		rx = target->un2ix(size/1.59588f);
-		ry = target->un2iy(size/1.59588f);
-		target->SetFill(&cf);
-		pts[0].x = pts[2].x = pts[4].x = ix;		
-		pts[0].y = pts[4].y = iy -ry;
-		pts[1].x = ix +rx;					pts[1].y = pts[3].y = iy;
-		pts[2].y = iy +ry;					pts[3].x = ix-rx;
-		target->oPolygon(pts, 5);
-		rx--;									ry--;
-		break;
-	case SYM_STAR:			//star is a combination of + and x symbols
-	case SYM_PLUS:			//draw a + sign
-	case SYM_HLINE:		case SYM_VLINE:
-		rx = target->un2ix(size/2.0f);
-		ry = target->un2iy(size/2.0f);
-		pts[0].x = pts[1].x = ix;
-		pts[0].y = iy - ry;					pts[1].y = iy + ry +1;
-		if(type != SYM_HLINE) target->oPolyline(pts, 2);
-		pts[0].x = ix -rx;					pts[1].x = ix + rx +1;
-		pts[0].y = pts[1].y = iy;
-		if(atype != SYM_VLINE) target->oPolyline(pts, 2);
-		if(atype == SYM_VLINE){ rx = 2; break;}
-		if(atype == SYM_HLINE){ ry = 2; break;}
-		if(atype == SYM_PLUS) break;		//continue with x symbol for star
-	case SYM_CROSS:			//draw a x symbol
-		rx = target->un2ix(size/2.5);
-		ry = target->un2iy(size/2.5);
-		pts[0].x = ix - rx;					pts[1].x = ix + rx;
-		pts[0].y = iy - ry;					pts[1].y = iy + ry;
-		target->oPolyline(pts, 2);
-		Swap(pts[0].y, pts[1].y);
-		target->oPolyline(pts, 2);
-		break;
-	case SYM_TEXT:
-		if(!SymTxt) Command(CMD_SETTEXT, (void *)"text", target);
-		if(!SymTxt || !SymTxt->text || !SymTxt->text[0])return;
-		SymTxt->iSize = target->un2iy(SymTxt->fSize = size *1.5);
-		target->SetTextSpec(SymTxt);
-		fmtText(target, ix, iy, SymTxt->text);
-		if (target->oGetTextExtent(SymTxt->text, 0, &rx, &ry)){
-			rx >>= 1;		ry >>= 1;
-			}
-		else rx = ry = 10;
-		}
-	rDims.left = ix-rx-1;				rDims.right = ix+rx+1;
-	rDims.top = iy-ry-1;				rDims.bottom = iy+ry+1;
-}
-
-bool 
-Symbol::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	char *tmptxt;
-	AccRange *ac;
-	int i, r, c;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(SymTxt) {
-			if(SymTxt->text) free(SymTxt->text);
-			free(SymTxt);
-			}
-		if(ssRef) free(ssRef);	ssRef = 0L;
-		if(name)free(name);		name = 0L;
-		return true;
-	case CMD_REDRAW:
-		//if we come here its most likely the result of Undo
-		if(parent && parent->Id==GO_REGRESSION)
-			return parent->Command(CMD_MRK_DIRTY, 0L, o);
-		return false;
-	case CMD_GETTEXT:
-		if(SymTxt && SymTxt->text && tmpl) {
-			strcpy((char*)tmpl, SymTxt->text);
-			return true;
-			}
-		return false;
-	case CMD_SYMTEXT_UNDO:
-		if(SymTxt && SymTxt->text){
-			Undo.String(this, &SymTxt->text, UNDO_CONTINUE);
-			if(tmpl) {
-				if(SymTxt->text = (char*)realloc(SymTxt->text, strlen((char*)tmpl))+2)
-					strcpy(SymTxt->text, (char*)tmpl);
-				}
-			else if(SymTxt->text) SymTxt->text[0] = 0;
-			return true;
-			}
-		//fall through if its new
-	case CMD_SYMTEXT:		case CMD_SETTEXT:
-		if(!SymTxt && (SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) {
-			SymTxt->ColTxt = SymLine.color;			SymTxt->fSize = size*1.5;
-			SymTxt->ColBg = parent ? parent->GetColor(COL_BG) : 0x00ffffffL;
-			SymTxt->Align = TXA_VCENTER | TXA_HCENTER;
-			SymTxt->Style = TXS_NORMAL;				SymTxt->Mode = TXM_TRANSPARENT;
-			SymTxt->Font = FONT_HELVETICA;			SymTxt->text = 0L;
-			}
-		if(!SymTxt) return false;
-		if(tmpl) {
-			if(SymTxt->text = (char*)realloc(SymTxt->text, strlen((char*)tmpl)+1))
-				strcpy(SymTxt->text, (char*)tmpl);
-			}
-		else if(SymTxt->text) SymTxt->text[0] = 0;
-		return true;
-	case CMD_SYM_TYPE:
-		if(tmpl)type = *((int*)tmpl);
-		return true;
-	case CMD_GETTEXTDEF:
-		if(!SymTxt || !tmpl) return false;
-		memcpy(tmpl, SymTxt, sizeof(TextDEF));
-		return true;
-	case CMD_SYMTEXTDEF:		case CMD_SETTEXTDEF:
-		if(!tmpl)return false;
-		if(SymTxt) tmptxt = SymTxt->text;
-		else tmptxt = 0L;
-		if(!SymTxt && !(SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) return false;
-		memcpy(SymTxt, tmpl, sizeof(TextDEF));
-		SymTxt->text = tmptxt;
-		return true;
-	case CMD_SYM_RANGETEXT:		case CMD_RANGETEXT:
-		if(!data || !tmpl) return false;
-		if(!(tmptxt = (char*)malloc(500)))return false;
-		if((ac = new AccRange((char*)tmpl)) && ac->GetFirst(&c, &r)) {
-			for(i = 0, tmptxt[0] = 0; i <= idx; i++) ac->GetNext(&c, &r);
-			data->GetText(r, c, tmptxt, 500);
-			delete(ac);
-			}
-		Command(CMD_SETTEXT, tmptxt, 0L);
-		free(tmptxt);
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_SYMBOL;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				o->ShowMark(&rDims, MRK_INVERT);
-				CurrGO = this;
-				return true;
-				}
-			break;
-			}
-		break;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >1 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bubbles are graphic objects
-Bubble::Bubble(GraphObj *par, DataObj *d, double x, double y, double s, int which, 
-	FillDEF *fill, LineDEF *outline, int xc, int xr, int yc, int yr, int sc,
-	int sr):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	fPos.fx = x;	fPos.fy = y;	fs = s;
-	type = which;
-	if(fill) {
-		memcpy(&BubbleFill,fill, sizeof(FillDEF));
-		if(BubbleFill.hatch) memcpy(&BubbleFillLine, BubbleFill.hatch, sizeof(LineDEF));
-		}
-	BubbleFill.hatch = &BubbleFillLine;
-	if(outline)memcpy(&BubbleLine, outline, sizeof(LineDEF));
-	Id = GO_BUBBLE;
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || sc >= 0 || sr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = sc;	ssRef[2].y = sr;
-			cssRef = 3;
-			}
-		}
-}
-
-Bubble::Bubble(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-Bubble::~Bubble()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-void
-Bubble::DoPlot(anyOutput *o)
-{
-	int x1, y1, x2, y2, ix, iy, tmp;
-	double fix, fiy;
-
-	o->SetLine(&BubbleLine);
-	o->SetFill(&BubbleFill);
-	switch(type & 0x0f0) {
-	case BUBBLE_UNITS:
-		fix = o->un2fix(fs);		fiy = o->un2fiy(fs);
-		break;
-	case BUBBLE_XAXIS:
-		fix = (o->fx2fix(fPos.fx+fs) - o->fx2fix(fPos.fx-fs))/2.0;
-		fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f));	//x and y resolution different ?
-		break;
-	case BUBBLE_YAXIS:
-		fix = (o->fy2fiy(fPos.fy-fs) - o->fy2fiy(fPos.fy+fs))/2.0;
-		fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f));	//x and y resolution different ?
-		break;
-		}
-	fix = fix < 0.0 ? -fix : fix;							//sign must be positive
-	fiy = fiy < 0.0 ? -fiy : fiy;
-	rDims.left = rDims.right = iround(o->fx2fix(fPos.fx));
-	rDims.top = rDims.bottom = iround(o->fy2fiy(fPos.fy));
-	switch(type & 0x00f) {
-	case BUBBLE_CIRCLE:
-		ix = (int)(fix/2.0);			iy = (int)(fiy/2.0);
-		tmp = iround(o->fx2fix(fPos.fx));		x1 = tmp - ix;		x2 = tmp + ix;
-		tmp = iround(o->fy2fiy(fPos.fy));		y1 = tmp - iy;		y2 = tmp + iy;
-		o->oCircle(x1, y1, x2, y2, name);
-		UpdateMinMaxRect(&rDims, x1, y1);	UpdateMinMaxRect(&rDims, x2, y2);
-		break;
-	case BUBBLE_SQUARE:
-		if((type & 0xf00) == BUBBLE_CIRCUM) {
-			ix = iround(fix*.392699081);		iy = iround(fiy*.392699081);
-			}
-		else if((type & 0xf00) == BUBBLE_AREA) {
-			ix = iround(fix*.443113462);		iy = iround(fiy*.443113462);
-			}
-		else {
-			ix = iround(fix*.353553391);		iy = iround(fiy*.353553391);
-			}
-		tmp = iround(o->fx2fix(fPos.fx));		x1 = tmp - ix;		x2 = tmp + ix;
-		tmp = iround(o->fy2fiy(fPos.fy));		y1 = tmp - iy;		y2 = tmp + iy;
-		o->oRectangle(x1, y1, x2, y2, name);
-		UpdateMinMaxRect(&rDims, x1, y1);	UpdateMinMaxRect(&rDims, x2, y2);
-		break;
-	case BUBBLE_UPTRIA:
-	case BUBBLE_DOWNTRIA:
-		if((type & 0xf00) == BUBBLE_CIRCUM) {
-			fix *= .523598775;		fiy *= .523598775;
-			}
-		else if((type & 0xf00) == BUBBLE_AREA) {
-			fix *= .673386843;		fiy *= .673386843;
-			}
-		else {
-			fix *=.433012702;		fiy *= .433012702;
-			}
-		ix =  iround(fix);		iy = iround(fiy*.57735);
-		tmp = iround(o->fx2fix(fPos.fx));
-		pts[0].x = pts[3].x = tmp - ix;		pts[1].x = tmp + ix;		pts[2].x = tmp;
-		tmp = iround(o->fy2fiy(fPos.fy));
-		if((type & 0x00f) == BUBBLE_UPTRIA) {
-			pts[0].y = pts[1].y = pts[3].y = tmp + iy;
-			pts[2].y = tmp - iround(fiy*1.1547);
-			}
-		else {
-			pts[0].y = pts[1].y = pts[3].y = tmp - iy;
-			pts[2].y = tmp + iround(fiy*1.1547);
-			}
-		o->oPolygon(pts, 4);
-		UpdateMinMaxRect(&rDims, pts[0].x, pts[0].y);
-		UpdateMinMaxRect(&rDims, pts[1].x, pts[2].y);
-		break;
-		}
-}
-
-void
-Bubble::DoMark(anyOutput *o, bool mark)
-{
-	if(mark) {
-		BubbleFillLine.color ^= 0x00ffffffL;
-		BubbleFill.color ^= 0x00ffffffL;
-		DoPlot(o);
-		BubbleFill.color ^= 0x00ffffffL;
-		BubbleFillLine.color ^= 0x00ffffffL;
-		}
-	else {
-		if(parent) parent->DoPlot(o);
-		else DoPlot(o);
-		}
-	o->UpdateRect(&rDims, false);
-}
-
-bool 
-Bubble::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	bool bSelected = false;
-	unsigned long n, s;
-	POINT p;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(ssRef) free(ssRef);	ssRef = 0L;
-		if(name)free(name);		name = 0L;
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&BubbleLine, &BubbleFill);
-		break;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, p.x = mev->x, p.y = mev->y) && !CurrGO) {
-				switch(type & 0x00f) {
-				case BUBBLE_CIRCLE:
-					n = s = p.x - ((rDims.right+rDims.left)>>1);
-					s *= n;
-					n = p.y - ((rDims.bottom+rDims.top)>>1);
-					n = isqr(s += n*n) -2;
-					bSelected = ((unsigned)((rDims.right-rDims.left)>>1) > n);
-					break;
-				case BUBBLE_SQUARE:
-					bSelected = true;
-					break;
-				case BUBBLE_UPTRIA:
-				case BUBBLE_DOWNTRIA:
-					if(!(bSelected = IsInPolygon(&p, pts, 4)))
-						bSelected = IsCloseToPL(p, pts, 4);
-					break;
-					}
-				if(bSelected) o->ShowMark(this, MRK_GODRAW);
-				return bSelected;
-				}
-			break;
-			}
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_BUBBLE;
-		data = (DataObj*)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >2 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &fs);
-			return true;
-			}
-		return false;
-	case CMD_BUBBLE_ATTRIB:
-		if(tmpl) {
-			type &= ~0xff0;
-			type |= (*((int*)tmpl) & 0xff0);
-			return true;
-			}
-		return false;
-	case CMD_BUBBLE_TYPE:
-		if(tmpl) {
-			type &= ~0x00f;
-			type |= (*((int*)tmpl) & 0x00f);
-			return true;
-			}
-		return false;
-	case CMD_BUBBLE_FILL:
-		if(tmpl) {
-			BubbleFill.type = ((FillDEF*)tmpl)->type;
-			BubbleFill.color = ((FillDEF*)tmpl)->color;
-			BubbleFill.scale = ((FillDEF*)tmpl)->scale;
-			if(((FillDEF*)tmpl)->hatch)
-				memcpy(&BubbleFillLine, ((FillDEF*)tmpl)->hatch, sizeof(LineDEF));
-			}
-		return true;
-	case CMD_BUBBLE_LINE:
-		if(tmpl) memcpy(&BubbleLine, tmpl, sizeof(LineDEF));
-		return true;
-	case CMD_AUTOSCALE:
-		return DoAutoscale(o);
-		break;
-		}
-	return false;
-}
 
-bool
-Bubble::DoAutoscale(anyOutput *o) 
+void *
+GraphObj::ObjThere(int x, int y)
 {
-	double dx, dy;
+	if(IsInRect(&rDims, x, y)) return this;
+	else return 0L;
+}
 
-	switch(type & 0x0f0) {
-	case BUBBLE_XAXIS:			case BUBBLE_YAXIS:
-		dx = dy = fs/2.0;		break;
-	case BUBBLE_UNITS:
-		dx = fPos.fx/20;		dy = fPos.fy/20;		break;
+void
+GraphObj::Track(POINT *p, anyOutput *o)
+{
+}
+
+double
+GraphObj::DefSize(int select)
+{
+	if(parent) return parent->DefSize(select);
+	else return defs.GetSize(select);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This is a special object to read certain svg-settings from a *.rlp file
+svgOptions::svgOptions(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(defs.svgScript) free(defs.svgScript);
+	if(defs.svgAttr) free(defs.svgAttr);
+	defs.svgScript = defs.svgAttr = 0L;
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		if(script) defs.svgScript = script;
+		if(svgattr) defs.svgAttr = svgattr;
+		script = svgattr = 0L;
 		}
-	((Plot*)parent)->CheckBounds(fPos.fx+dx, fPos.fy-dy);
-	((Plot*)parent)->CheckBounds(fPos.fx-dx, fPos.fy+dy);
-	return true;
+	Id=GO_SVGOPTIONS;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bars are graphic objects
-Bar::Bar(GraphObj *par, DataObj *d, double x, double y, int which,int xc, int xr,
-		int yc, int yr):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	parent = par;
-	fPos.fx = x;
-	fPos.fy = y;
-	type = which;
-	if(type & BAR_RELWIDTH) size = 60.0;
-	data = d;
-	Id = GO_BAR;
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			cssRef = 2;
-			}
-		}
-}
-
-Bar::Bar(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-Bar::~Bar()
-{
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-double
-Bar::GetSize(int select)
-{
-	switch(select){
-	case SIZE_XPOS:				return fPos.fx;
-	case SIZE_YPOS:				return fPos.fy;
-		}
-	return 0.0;
-}
-
-bool
-Bar::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_BAR: 
-		size = value;
-		return true;
-	case SIZE_BAR_LINE:
-		BarLine.width = value;
-		return true;
-	case SIZE_XBASE:
-		BarBase.fx = value;
-		return true;
-	case SIZE_YBASE:
-		BarBase.fy = value;
-		return true;
-		}
-	return false;
-}
-
-bool
-Bar::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_BAR_LINE:
-		BarLine.color = col;
-		return true;
-	case COL_BAR_FILL:
-		BarFill.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-Bar::DoPlot(anyOutput *target)
-{
-	int w;
-	double fBase, rsize;
-	POINT pts[2];
-
-	if(!parent || size <= 0.001) return;
-	target->SetLine(&BarLine);
-	target->SetFill(&BarFill);
-	switch(type & 0xff) {
-	case BAR_VERTU:		case BAR_VERTT:		case BAR_VERTB:
-		switch(type & 0xff) {
-		case BAR_VERTB:
-			fBase = parent->GetSize(SIZE_BOUNDS_BOTTOM);
-			break;
-		case BAR_VERTT:
-			fBase = parent->GetSize(SIZE_BOUNDS_TOP);
-			break;
-		case BAR_VERTU:
-			fBase = BarBase.fy;
-			break;
-			}
-		if(type & BAR_RELWIDTH) {
-			rsize = size * parent->GetSize(SIZE_BARMINX)/100.0;
-			pts[0].x = iround(target->fx2fix(fPos.fx - rsize/2.0));
-			pts[1].x = iround(target->fx2fix(fPos.fx + rsize/2.0));
-			}
-		else {
-			w = target->un2ix(size);
-			pts[0].x = iround(target->fx2fix(fPos.fx)) - (w>>1);
-			pts[1].x = pts[0].x + w;
-			}
-		if(type & BAR_CENTERED) {
-			pts[0].y = iround(target->fy2fiy(fBase - (fPos.fy - fBase)));
-			pts[1].y = iround(target->fy2fiy(fBase + (fPos.fy - fBase)));
-			}
-		else {
-			pts[0].y = iround(target->fy2fiy(fBase));
-			pts[1].y = iround(target->fy2fiy(fPos.fy));
-			}
-		break;
-	case BAR_HORU:		case BAR_HORR:		case BAR_HORL:
-		switch(type & 0xff) {
-		case BAR_HORL:
-			fBase = parent->GetSize(SIZE_BOUNDS_LEFT);
-			break;
-		case BAR_HORR:
-			fBase = parent->GetSize(SIZE_BOUNDS_RIGHT);
-			break;
-		case BAR_HORU:
-			fBase = BarBase.fx;
-			break;
-			}
-		if(type & BAR_RELWIDTH) {
-			rsize = size * parent->GetSize(SIZE_BARMINY)/100.0;
-			pts[0].y = iround(target->fy2fiy(fPos.fy - rsize/2.0));
-			pts[1].y = iround(target->fy2fiy(fPos.fy + rsize/2.0));
-			}
-		else {
-			w = target->un2iy(size);
-			pts[0].y = target->fy2iy(fPos.fy) - w/2;
-			pts[1].y = pts[0].y+w;
-			}
-		if(type & BAR_CENTERED) {
-			pts[0].x = target->fx2ix(fBase - (fPos.fx - fBase));
-			pts[1].x = target->fx2ix(fBase + (fPos.fx - fBase));
-			}
-		else {
-			pts[0].x = target->fx2ix(fBase);
-			pts[1].x = target->fx2ix(fPos.fx);
-			}
-		break;
-	default:
-		return;
-		}
-	if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
-		target->oSolidLine(pts);
-		}
-	else target->oRectangle(pts[0].x, pts[0].y, pts[1].x, pts[1].y, name);
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-}
 
-void
-Bar::DoMark(anyOutput *o, bool mark)
+svgOptions::~svgOptions()
 {
-	int i;
+	if(script)free(script);
+	script = 0L;
+}
 
-	if(mark){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		i = 2*o->un2ix(BarLine.width);		//increase size of rectangle for marks
-		IncrementMinMaxRect(&mrc, i);
-		mo = GetRectBitmap(&mrc, o);
-		o->CopyBitmap(mrc.left, mrc.top, mo, 0, 0, mrc.right-mrc.left, mrc.bottom - mrc.top, true);
-		o->UpdateRect(&mrc, false);
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Symbols are graphic objects
+Symbol::Symbol(GraphObj *par, DataObj *d, double x, double y, int which,
+		int xc, int xr, int yc, int yr):GraphObj(par, d)
+{
+	//Symbols with no parent are part of a dialog
+	FileIO(INIT_VARS);
+	fPos.fx = x;
+	fPos.fy = y;
+	type = which;
+	Id = GO_SYMBOL;
+	if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			cssRef = 2;
+			}
 		}
-	else RestoreRectBitmap(&mo, &mrc, o);
 }
-
-bool 
-Bar::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	FillDEF *TmpFill;
-	lfPOINT bl;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name)free(name);			name = 0L;
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&BarLine, &BarFill);
-		break;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				o->ShowMark(CurrGO = this, MRK_GODRAW);
-				return true;
-				}
-			break;
-			}
-		return false;
-	case CMD_BAR_FILL:
-		TmpFill = (FillDEF *)tmpl;
-		if(TmpFill) {
-			BarFill.type = TmpFill->type;
-			BarFill.color = TmpFill->color;
-			BarFill.scale = TmpFill->scale;
-			if(TmpFill->hatch) memcpy(&HatchLine, TmpFill->hatch, sizeof(LineDEF));
-			}
-		return true;
-	case CMD_BAR_TYPE:
-		if(tmpl) type = *((int*)tmpl);
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_BAR;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >1 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-			switch(type & 0xff) {
-			case BAR_VERTU:
-			case BAR_VERTT:
-			case BAR_VERTB:
-				bl.fx = fPos.fx;
-				switch (type & 0xff) {
-				case BAR_VERTU:
-					bl.fy = BarBase.fy;
-					break;
-				case BAR_VERTT:
-				case BAR_VERTB:
-					bl.fy = 0.0f;		//cannot resolve
-					break;
-					}
-				if(type & BAR_CENTERED) bl.fy -= fPos.fy;
-				break;
-			case BAR_HORU:
-			case BAR_HORR:
-			case BAR_HORL:
-				bl.fy = fPos.fy;
-				switch(type & 0xff) {
-				case BAR_HORU:
-					bl.fx = BarBase.fx;
-				case BAR_HORR:
-				case BAR_HORL:
-					bl.fx = 0.0f;		//cannot resolve
-					}
-				if(type & BAR_CENTERED) bl.fx -= fPos.fx;
-				break;
-				}
-			((Plot*)parent)->CheckBounds(bl.fx, bl.fy);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Data line is a graphic object
-DataLine::DataLine(GraphObj *par, DataObj *d, char *xrange, char *yrange):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	Id = GO_DATALINE;
-	if(xrange)ssXref = strdup(xrange);	if(yrange)ssYref = strdup(yrange);
-	SetValues();
-}
-	
-DataLine::DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	Values = val;			nPnt = nval;	nPntSet = nPnt-1;
-	Id = GO_DATALINE;
-}
-
-DataLine::DataLine(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-DataLine::~DataLine()
-{
-	if(Values)free(Values);		Values = 0L;
-	if(pts) free(pts);			pts = 0L;
-	if(ssXref) free(ssXref);	ssXref = 0L;
-	if(ssYref) free(ssYref);	ssYref = 0L;
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
-}
-
-bool
-DataLine::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_DATA_LINE:
-		LineDef.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-DataLine::DoPlot(anyOutput *target)
-{
-	int i;
-	lfPOINT fip;
-	POINT pn, *tmppts;
-
-	if(!Values || nPntSet < 1) return;
-	if (nPntSet >= nPnt) nPntSet = nPnt-1;
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	if(pts) free(pts);				pts = 0L;
-	if((type & 0xff) == 9 || (type & 0xff) == 10) //splines
-		pts = (POINT *)malloc(sizeof(POINT)*1000);
-	else if(type & 0xff) pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2)*2);
-	else pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2));
-	if(!pts) return;
-	if(max.fx > min.fx && max.fy > min.fy) dirty = false;
-	else if(dirty) Command(CMD_AUTOSCALE, 0L, target);
-	cp = 0;
-	switch(type & 0x0f) {
-	case 0:		default:
-		for (i = 0; i <= nPntSet; i++){
-			target->fp2fip(Values+i, &fip);
-			pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-			AddToPolygon(&cp, pts, &pn);
-			}
-		break;
-	case 5:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		target->fp2fip(Values+1, &fip);
-		pn.y += (pn.y -iround(fip.fy))>>1;
-		AddToPolygon(&cp, pts, &pn);
-	case 1:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(+fip.fy);
-		for (i = 0; i <= nPntSet; i++){
-			target->fp2fip(Values+i, &fip);
-			pn.x = iround(fip.fx);			AddToPolygon(&cp, pts, &pn);
-			pn.y = iround(fip.fy);			AddToPolygon(&cp, pts, &pn);
-			}
-		if((type &0xf) == 5) {
-			target->fp2fip(Values+i-2, &fip);
-			pn.x += (pn.x - iround(fip.fx))>>1;
-			AddToPolygon(&cp, pts, &pn);
-			}
-		break;
-	case 6:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		target->fp2fip(Values+1, &fip);
-		pn.x += (pn.x - iround(fip.fx))>>1;
-		AddToPolygon(&cp, pts, &pn);
-	case 2:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		for (i = 0; i <= nPntSet; i++){
-			target->fp2fip(Values+i, &fip);
-			pn.y = iround(fip.fy);			AddToPolygon(&cp, pts, &pn);
-			pn.x = iround(fip.fx);			AddToPolygon(&cp, pts, &pn);
-			}
-		if((type &0xf) == 6) {
-			target->fp2fip(Values+i-2, &fip);
-			pn.y += (pn.y - iround(fip.fy))>>1;
-			AddToPolygon(&cp, pts, &pn);
-			}
-		break;
-	case 7:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		target->fp2fip(Values+1, &fip);
-		pn.x += (pn.x - iround(fip.fx))>>1;
-		AddToPolygon(&cp, pts, &pn);
-	case 3:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		for (i = 0; i <= nPntSet; i++){
-			target->fp2fip(Values+i, &fip);
-			pn.x = (pn.x + iround(fip.fx))>>1;	AddToPolygon(&cp, pts, &pn);
-			pn.y = iround(fip.fy);				AddToPolygon(&cp, pts, &pn);
-			pn.x = iround(fip.fx);
-			}
-		AddToPolygon(&cp, pts, &pn);
-		if((type &0xf) == 7) {
-			target->fp2fip(Values+i-2, &fip);
-			pn.x += (pn.x - iround(fip.fx))>>1;
-			AddToPolygon(&cp, pts, &pn);
-			}
-		break;
-	case 8:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		target->fp2fip(Values+1, &fip);
-		pn.y += (pn.y - iround(fip.fy))>>1;
-		AddToPolygon(&cp, pts, &pn);
-	case 4:
-		target->fp2fip(Values, &fip);
-		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
-		for (i = 0; i <= nPntSet; i++){
-			target->fp2fip(Values+i, &fip);
-			pn.y = (pn.y + iround(fip.fy))>>1;	AddToPolygon(&cp, pts, &pn);
-			pn.x = iround(fip.fx);				AddToPolygon(&cp, pts, &pn);
-			pn.y = iround(fip.fy);
-			}
-		AddToPolygon(&cp, pts, &pn);
-		if((type &0xf) == 8) {
-			target->fp2fip(Values+i-2, &fip);
-			pn.y += (pn.y - iround(fip.fy))>>1;
-			AddToPolygon(&cp, pts, &pn);
-			}
-		break;
-	case 9:		case 10:
-		DrawSpline(target);
-		break;
-		}
-	if(cp < 2) return;
-	if(isPolygon) {			//for mark polygon only !!
-		AddToPolygon(&cp, pts, pts);
-		}
-	else{
-		target->SetLine(&LineDef);		target->oPolyline(pts, cp);
-		}
-	if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
-	i = 2*target->un2ix(LineDef.width);		//increase size of rectangle for marks
-	IncrementMinMaxRect(&rDims, i);
-}
-
-void
-DataLine::DoMark(anyOutput *o, bool mark)
-{
-	if(pts && cp && o){
-		if(mark){
-			memcpy(&mrc, &rDims, sizeof(RECT));
-			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
-			mo = GetRectBitmap(&mrc, o);
-			InvertLine(pts, cp, &LineDef, &mrc, o, mark);
-			}
-		else if(mo) RestoreRectBitmap(&mo, &mrc, o);
-		}
-}
-
-bool
-DataLine::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	bool bFound = false;
-	POINT p1;
-	int i;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPntSet <1)
-				return false; 
-			if(isPolygon && IsInPolygon(&p1, pts, cp)) bFound = true;
-			if(bFound || IsCloseToPL(p1,pts,cp)) 
-				return o->ShowMark(this, MRK_GODRAW);
-			}
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE;
-		data = (DataObj*)tmpl;
-		return true;
-	case CMD_MRK_DIRTY:
-		dirty= true;
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, 0L);
-		return false;
-	case CMD_LEGEND:
-		if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
-			if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L);
-			}
-		break;
-	case CMD_SET_LINE:
-		if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
-		return true;
-	case CMD_UPDATE:
-		Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
-		Undo.ValLong(this, &nPntSet, UNDO_CONTINUE);
-		SetValues();
-		return true;
-	case CMD_AUTOSCALE:
-		if(nPntSet < 1 || !Values) return false;
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			if(dirty) {
-				min.fx = max.fx = Values[0].fx;	min.fy = max.fy = Values[0].fy;
-				for (i = 1; i <= nPntSet; i++){
-					min.fx = Values[i].fx < min.fx ? Values[i].fx : min.fx;
-					max.fx = Values[i].fx > max.fx ? Values[i].fx : max.fx;
-					min.fy = Values[i].fy < min.fy ? Values[i].fy : min.fy;
-					max.fy = Values[i].fy > max.fy ? Values[i].fy : max.fy;
-					}
-				}
-			((Plot*)parent)->CheckBounds(min.fx, min.fy);
-			((Plot*)parent)->CheckBounds(max.fx, max.fy);
-			dirty = false;
-			return true;
-			}
-		return false;
-		}
-	return false;
-}
-
-void
-DataLine::SetValues()
-{
-	AccRange *rX, *rY1=0L, *rY2=0L;
-	int i, j, k, l, m, n;
-	double x, y;
-	char *yref1 = 0L, *yref2 = 0L;
-	lfPOINT *tmpValues = Values;
-
-	if(!ssXref || !ssYref) return;
-	if(!(yref1 = strdup(ssYref)))return;
-	for(i = 0; yref1[i]; i++) {
-		if(yref1[i] == ';') {
-			yref1[i++] = 0;
-			while(yref1[i] && yref1[i] < 33) i++;
-			yref2 = strdup(yref1+i);
-			}
-		}
-	nPnt = nPntSet = 0;
-	min.fx = min.fy = HUGE_VAL;		max.fx = max.fy = -HUGE_VAL;
-	rX = new AccRange(ssXref);		rY1 = new AccRange(yref1);
-	if(!rX || !rY1){
-		if(yref1) free(yref1);		if(yref2) free(yref2);
-		if(rX) delete(rX);	if(rY1) delete(rY1);
-		return;
-		}
-	if(yref2 &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) {
-		if(!(Values = (lfPOINT *)realloc(Values, ((nPnt*2+2) * sizeof(lfPOINT))))) return; 
-		if(!(rY2 = new AccRange(yref2))) {
-			if(yref1) free(yref1);		if(yref2) free(yref2);
-			if(rX) delete(rX);	if(rY1) delete(rY1);
-			return;
-			}
-		if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && 
-			rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) &&
-			rY2->GetFirst(&m, &n) && rY2->GetNext(&m, &n)) do {
-			if(data->GetValue(j, i, &x)){
-				if(data->GetValue(l, k, &y)){
-					Values[nPntSet].fx = x;			Values[nPntSet++].fy = y;
-					}
-				if(data->GetValue(n, m, &y)){
-					Values[nPntSet].fx = x;			Values[nPntSet++].fy = y;
-					}
-				}
-			}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&m, &n));
-		}
-	else {
-		if((nPnt = rX->CountItems()) != (rY1->CountItems())) return;
-		if(!(Values = (lfPOINT *)realloc(Values, (nPnt+2) * sizeof(lfPOINT)))) return; 
-		if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && 
-			rX->GetNext(&i, &j) && rY1->GetNext(&k, &l)) do {
-			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
-				Values[nPntSet].fx = x;				Values[nPntSet++].fy = y;
-				}
-			}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
-		}
-	nPnt = nPntSet;		nPntSet--;	dirty = true;
-	Command(CMD_AUTOSCALE, 0L, 0L);
-	if(tmpValues && Values != tmpValues) Undo.InvalidGO(this);
-	if(rX) delete(rX);	if(rY1) delete(rY1);	if(rY2) delete(rY2);
-	if(yref1) free(yref1);	if(yref2) free(yref2);
-}
-
-void
-DataLine::LineData(lfPOINT *val, long nval)
+
+Symbol::Symbol(int src):GraphObj(0L, 0L)
 {
-	lfPOINT *ov = Values;
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		SymFill.hatch = (LineDEF *) NULL;
+		}
+}
 
-	if(!val || nval <2) return;
-	if(nval > nPnt && nPnt > 1 && Values){
-		if(!(Values = (lfPOINT *)realloc(Values, ((nval*2+2) * sizeof(lfPOINT))))) return; 
-		if(ov != Values) Undo.InvalidGO(this);
-		}
-	else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
-	memcpy(Values, val, nval * sizeof(lfPOINT));
-	if(pts) free(pts);			pts = 0L;				dirty = true;			
-	free(val);					nPnt = nval;				nPntSet = nPnt-1;
-}
+Symbol::~Symbol()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+}
 
-void
-DataLine::DrawCurve(anyOutput *target)
+double
+Symbol::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_MINE:
+	case SIZE_SYMBOL:
+		return size;
+	case SIZE_SYM_LINE:
+		return SymLine.width;
+	case SIZE_XPOS:
+		return fPos.fx;
+	case SIZE_YPOS:
+		return fPos.fy;
+	default:
+		return DefSize(select);
+		}
+}
+
+bool
+Symbol::SetSize(int select, double value)
+{
+	switch(select & 0xfff){
+	case SIZE_MINE:
+	case SIZE_SYMBOL:
+		size = value;
+		return true;
+	case SIZE_SYM_LINE:
+		SymLine.width = value;
+		return true;
+	case SIZE_XPOS:
+		fPos.fx = value;
+		return true;
+	case SIZE_YPOS:
+		fPos.fy = value;
+		return true;
+	}
+	return false;
+}
+
+DWORD
+Symbol::GetColor(int select)
 {
+	switch(select) {
+	case COL_SYM_LINE:
+		return SymLine.color;
+	case COL_SYM_FILL:
+		return SymFill.color;
+	default:
+		return parent ? parent->GetColor(select) : defs.Color(select);
+		}
+}
+
+bool
+Symbol::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_SYM_LINE:
+		SymLine.color = col;
+		if(SymTxt) SymTxt->ColTxt = col;
+		return true;
+	case COL_SYM_FILL:
+		SymFill.color = col;
+		return true;
+	default:
+		return false;
+		}
 }
 
 void
-DataLine::DrawSpline(anyOutput *target)
+Symbol::DoPlot(anyOutput *target)
 {
-	int i, j, k, klo, khi, ptsize = 1000;
-	double *y2, min, max, x, y, h, b, a;
-	POINT pn;
-	lfPOINT *scvals;
-	
-	if(!(y2 = (double*)malloc(sizeof(double)*(nPnt)))) return;
-	if(!(scvals = (lfPOINT*)malloc(sizeof(lfPOINT)*(nPnt)))){
-		free(y2);
-		return;
+	int ix, iy, rx, ry, atype;
+	lfPOINT fip;
+	POINT pts[5];
+	FillDEF cf;
+
+	if(size <= 0.001) return;
+	atype = (type  & 0xfff);
+	memcpy(&cf, &SymFill, sizeof(FillDEF));
+	if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
+		atype == SYM_TRIADF || atype == SYM_DIAMONDF) cf.color = SymLine.color;
+	if(type & SYM_POS_PARENT) {
+		if(!parent) return;
+		fip.fx = parent->GetSize(SIZE_XCENTER);
+		fip.fy = parent->GetSize(SIZE_YCENTER);
 		}
-	if((type & 0x0f) == 9 || (type & 0x0f) == 10) {
-		if((type & 0x0f) == 9) for(i = 0; i < nPnt; i++) {
-			scvals[i].fx = target->fx2fix(Values[i].fx);
-			scvals[i].fy = target->fy2fiy(Values[i].fy);
+	else if(!target->fp2fip(&fPos, &fip)) return;
+	ix = iround(fip.fx);		iy = iround(fip.fy);
+	target->SetLine(&SymLine);
+	switch(atype){
+	default:
+	case SYM_CIRCLE:		//circle
+	case SYM_CIRCLEF:		//filled circle
+		rx = target->un2ix(size/2.0);		ry = target->un2iy(size/2.0); 
+		target->SetFill(&cf);
+		target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+		rx--;ry--;			//smaller marking rectangle
+		break;
+	case SYM_RECT:			//rectange (square)
+	case SYM_RECTF:			//filled rectangle
+		rx = target->un2ix(size/2.25676);
+		ry = target->un2iy(size/2.25676);
+		target->SetFill(&cf);
+		target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+		break;
+	case SYM_TRIAU:			//triangles up and down, open or closed
+	case SYM_TRIAUF:	case SYM_TRIAD:		case SYM_TRIADF:
+		rx = target->un2ix(size/1.48503);
+		ry = target->un2iy(size/1.48503);
+		target->SetFill(&cf);
+		pts[0].x = pts[3].x = ix - rx;		pts[1].x = ix;		pts[2].x = ix+rx;
+		if(atype == SYM_TRIAU || atype == SYM_TRIAUF) {		//patch by anonymous
+			pts[0].y = pts[2].y = pts[3].y = iy+target->un2iy(size*0.38878f);
+			pts[1].y = iy-target->un2iy(size*0.77756f);
 			}
-		else for(i = 0; i < nPnt; i++) {
-			scvals[i].fy = target->fx2fix(Values[i].fx);
-			scvals[i].fx = target->fy2fiy(Values[i].fy);
+		else {
+			pts[0].y = pts[2].y = pts[3].y = iy-target->un2iy(size*0.38878f);
+			pts[1].y = iy+target->un2iy(size*0.77756f);
 			}
-		SortFpArray(nPnt, scvals);
-		min = scvals[0].fx;			max = scvals[nPnt-1].fx;
-		for(i = j = 0; i < (nPnt-1); i++, j++) {
-			y = scvals[i].fy;			scvals[j].fx = scvals[i].fx;
-			for(k = 1; scvals[i+1].fx == scvals[i].fx; k++) {
-				y += scvals[i+1].fy;		i++;
-				}
-			scvals[j].fy = y/((double)k);
+		target->oPolygon(pts, 4);
+		rx--; ry--;
+		break;
+	case SYM_DIAMOND:	case SYM_DIAMONDF:
+		rx = target->un2ix(size/1.59588f);
+		ry = target->un2iy(size/1.59588f);
+		target->SetFill(&cf);
+		pts[0].x = pts[2].x = pts[4].x = ix;		
+		pts[0].y = pts[4].y = iy -ry;
+		pts[1].x = ix +rx;					pts[1].y = pts[3].y = iy;
+		pts[2].y = iy +ry;					pts[3].x = ix-rx;
+		target->oPolygon(pts, 5);
+		rx--;									ry--;
+		break;
+	case SYM_STAR:			//star is a combination of + and x symbols
+	case SYM_PLUS:			//draw a + sign
+	case SYM_HLINE:		case SYM_VLINE:
+		rx = target->un2ix(size/2.0f);
+		ry = target->un2iy(size/2.0f);
+		pts[0].x = pts[1].x = ix;
+		pts[0].y = iy - ry;					pts[1].y = iy + ry +1;
+		if(type != SYM_HLINE) target->oPolyline(pts, 2);
+		pts[0].x = ix -rx;					pts[1].x = ix + rx +1;
+		pts[0].y = pts[1].y = iy;
+		if(atype != SYM_VLINE) target->oPolyline(pts, 2);
+		if(atype == SYM_VLINE){ rx = 2; break;}
+		if(atype == SYM_HLINE){ ry = 2; break;}
+		if(atype == SYM_PLUS) break;		//continue with x symbol for star
+	case SYM_CROSS:			//draw a x symbol
+		rx = target->un2ix(size/2.5);
+		ry = target->un2iy(size/2.5);
+		pts[0].x = ix - rx;					pts[1].x = ix + rx;
+		pts[0].y = iy - ry;					pts[1].y = iy + ry;
+		target->oPolyline(pts, 2);
+		Swap(pts[0].y, pts[1].y);
+		target->oPolyline(pts, 2);
+		break;
+	case SYM_TEXT:
+		if(!SymTxt) Command(CMD_SETTEXT, (void *)"text", target);
+		if(!SymTxt || !SymTxt->text || !SymTxt->text[0])return;
+		SymTxt->iSize = target->un2iy(SymTxt->fSize = size *1.5);
+		target->SetTextSpec(SymTxt);
+		fmtText(target, ix, iy, SymTxt->text);
+		if (target->oGetTextExtent(SymTxt->text, 0, &rx, &ry)){
+			rx >>= 1;		ry >>= 1;
 			}
-		if(scvals[i].fx > scvals[i-1].fx) {
-			scvals[j].fx = scvals[i].fx;	scvals[j].fy = scvals[i].fy;
-			j++;
+		else rx = ry = 10;
+		}
+	rDims.left = ix-rx-1;				rDims.right = ix+rx+1;
+	rDims.top = iy-ry-1;				rDims.bottom = iy+ry+1;
+}
+
+bool 
+Symbol::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	char *tmptxt;
+	AccRange *ac;
+	int i, r, c;
+
+	switch (cmd) {
+	case CMD_SCALE:
+		if(!tmpl) return false;
+		size *= ((scaleINFO*)tmpl)->sy.fy;
+		SymLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		if(SymTxt) {
+			SymTxt->fSize *= ((scaleINFO*)tmpl)->sy.fy;
+			SymTxt->iSize = 0;
 			}
-		spline(scvals, j, y2);
-		h = scvals[1].fx - scvals[0].fx;	// klo and khi bracket the input value of x
-		for(x = min, klo = 0, i = khi = 1; x < max && i < j; x += 1.0) {
-			while(x > scvals[i].fx) {
-				klo++;		khi++;	i++;
-				h = scvals[khi].fx - scvals[klo].fx;
-				}
-			a = (scvals[khi].fx - x) / h;		b = (x - scvals[klo].fx) / h;
-			y = a * scvals[klo].fy + b * scvals[khi].fy + ((a*a*a - a) * y2[klo] + (b*b*b - b) * y2[khi]) * (h*h)/6.0;
-			if((type & 0x0f) == 9) {
-				pn.x = iround(x);		pn.y = iround(y);
-				}
-			else {
-				pn.x = iround(y);		pn.y = iround(x);
+		return true;
+	case CMD_FLUSH:
+		if(SymTxt) {
+			if(SymTxt->text) free(SymTxt->text);
+			free(SymTxt);
+			}
+		if(ssRef) free(ssRef);	ssRef = 0L;
+		if(name)free(name);		name = 0L;
+		return true;
+	case CMD_REDRAW:
+		//if we come here its most likely the result of Undo
+		if(parent && parent->Id==GO_REGRESSION)
+			return parent->Command(CMD_MRK_DIRTY, 0L, o);
+		return false;
+	case CMD_GETTEXT:
+		if(SymTxt && SymTxt->text && tmpl) {
+			rlp_strcpy((char*)tmpl, 50, SymTxt->text);
+			return true;
+			}
+		return false;
+	case CMD_SYMTEXT_UNDO:
+		if(SymTxt && SymTxt->text){
+			c = Undo.String(this, &SymTxt->text, UNDO_CONTINUE);
+			i = (int)strlen((char*)tmpl);		i = i > c ? i+2 : c+2;
+			if(tmpl) {
+				if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (char*)tmpl);
 				}
-			if(cp >= ptsize) {
-				ptsize += 1000;
-				pts = (POINT*)realloc(pts, sizeof(POINT)*ptsize); 
+			else if(SymTxt->text) SymTxt->text[0] = 0;
+			return true;
+			}
+		//fall through if its new
+	case CMD_SYMTEXT:		case CMD_SETTEXT:
+		if(!SymTxt && (SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) {
+			SymTxt->ColTxt = SymLine.color;			SymTxt->fSize = size*1.5;
+			SymTxt->ColBg = parent ? parent->GetColor(COL_BG) : 0x00ffffffL;
+			SymTxt->Align = TXA_VCENTER | TXA_HCENTER;
+			SymTxt->Style = TXS_NORMAL;				SymTxt->Mode = TXM_TRANSPARENT;
+			SymTxt->Font = FONT_HELVETICA;			SymTxt->text = 0L;
+			}
+		if(!SymTxt) return false;
+		if(tmpl) {
+			i = (int) strlen((char*)tmpl) + 2;
+			if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (char*)tmpl);
+			}
+		else if(SymTxt->text) SymTxt->text[0] = 0;
+		return true;
+	case CMD_SYM_TYPE:
+		if(tmpl)type = *((int*)tmpl);
+		return true;
+	case CMD_GETTEXTDEF:
+		if(!SymTxt || !tmpl) return false;
+		memcpy(tmpl, SymTxt, sizeof(TextDEF));
+		return true;
+	case CMD_SYMTEXTDEF:		case CMD_SETTEXTDEF:
+		if(!tmpl)return false;
+		if(SymTxt) tmptxt = SymTxt->text;
+		else tmptxt = 0L;
+		if(!SymTxt && !(SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) return false;
+		memcpy(SymTxt, tmpl, sizeof(TextDEF));
+		SymTxt->text = tmptxt;
+		return true;
+	case CMD_SYM_RANGETEXT:		case CMD_RANGETEXT:
+		if(!data || !tmpl) return false;
+		if(!(tmptxt = (char*)malloc(500)))return false;
+		if((ac = new AccRange((char*)tmpl)) && ac->GetFirst(&c, &r)) {
+			for(i = 0, tmptxt[0] = 0; i <= idx; i++) ac->GetNext(&c, &r);
+			data->GetText(r, c, tmptxt, 500);
+			delete(ac);
+			}
+		Command(CMD_SETTEXT, tmptxt, 0L);
+		free(tmptxt);
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_SYMBOL;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				o->ShowMark(&rDims, MRK_INVERT);
+				CurrGO = this;
+				return true;
 				}
-			AddToPolygon(&cp, pts, &pn);
+			break;
+			}
+		break;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >1 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+			return true;
 			}
+		break;
 		}
-	free(y2);	free(scvals);
+	return false;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// DataPolygon is a graphic object based on DataLine
-DataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange):
-	DataLine(par, d, xrange, yrange)
-{
-	lfPOINT *fp = Values;
-	char *rx = ssXref;
-	char *ry = ssYref;
-
-	FileIO(INIT_VARS);
-	Values = fp;				//FileIO will just set Values to 0L !
-	ssXref = rx;			ssYref = ry;
-	Id = GO_DATAPOLYGON;
-}
-
-DataPolygon::DataPolygon(int src):DataLine(0L, 0)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-DataPolygon::~DataPolygon()
-{
-	if(Values)free(Values);		Values =0L;
-	if(pts) free (pts);			pts = 0L;
-	if(ssXref) free(ssXref);	ssXref = 0L;
-	if(ssYref) free(ssYref);	ssYref = 0L;
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
-}
-
-void
-DataPolygon::DoPlot(anyOutput *target)
-{
-	if(!Values || nPntSet < 2) return;
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	DataLine::DoPlot(target);	//no drawing but fill pts only
-	target->SetLine(&LineDef);	target->SetFill(&pgFill);
-	target->oPolygon(pts, cp);
-}
-
-void
-DataPolygon::DoMark(anyOutput *o, bool mark)
-{
-	if(pts && cp && o){
-		if(mark){
-			memcpy(&mrc, &rDims, sizeof(RECT));
-			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
-			mo = GetRectBitmap(&mrc, o);
-			InvertPolygon(pts, cp, &LineDef, &pgFill, &mrc, o, mark);
-			}
-		else RestoreRectBitmap(&mo, &mrc, o);
-		}
-}
-
-bool
-DataPolygon::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	switch (cmd) {
-	case CMD_PG_FILL:
-		if(tmpl) {
-			memcpy((void*)&pgFill, tmpl, sizeof(FillDEF));
-			if(pgFill.hatch) memcpy((void*)&pgFillLine, (void*)pgFill.hatch, sizeof(LineDEF));
-			pgFill.hatch = (LineDEF*)&pgFillLine;
-			}
-		return true;
-	case CMD_LEGEND:
-		if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
-			if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill);
-			}
-		break;
-	default:
-		return DataLine::Command(cmd, tmpl, o);
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Calculate and display a regression line
-// Ref.: "Biometry" third edition 1995 (ed. R.R. Sokal and F.J. Rohlf),
-// W.H. Freeman and Company, New York; ISBN 0-7167-2411-1; pp. 451ff
-RegLine::RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
-	GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	type = sel;
-	Id = GO_REGLINE;
-	uclip.Xmin = uclip.Ymin = lim.Xmin = lim.Ymin = -1.0;
-	uclip.Xmax = uclip.Ymax = lim.Xmax = lim.Ymax = 1.0;
-	Recalc(values, n);
-}
-
-RegLine::RegLine(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) FileIO(FILE_READ);
-}
-
-RegLine::~RegLine()
-{
-	if(pts) free(pts);
-	pts = 0L;
-	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
-}
-
-double
-RegLine::GetSize(int select)
-{
-	double a, b;
-
-	switch(select) {
-	case SIZE_MX:		return mx;
-	case SIZE_MY:		return my;
-	case SIZE_A:
-	case SIZE_B:
-		switch(type & 0x07) {
-		case 1:		a = l2.fx;	b = l2.fy;	break;
-		case 2:		a = l3.fx;	b = l3.fy;	break;
-		case 3:		a = l4.fx;	b = l4.fy;	break;
-		case 4:		a = l5.fx;	b = l5.fy;	break;
-		default:	a = l1.fx;	b = l1.fy;	break;
-			}
-		if(select == SIZE_A) return a;
-		else return b;
-		}
-	return 0.0;
-}
-
-void
-RegLine::DoPlot(anyOutput *o)
-{
-	int i;
-	POINT pn, *tmppts;
-	double x, x1, y, d, a, b;
-	fRECT cliprc;
-	bool dValid;
-
-	switch (type & 0x70) {
-	case 0x20:	memcpy(&cliprc, &uclip, sizeof(fRECT));		break;
-	case 0x10:
-		if(parent) {
-			cliprc.Xmin = parent->GetSize(SIZE_BOUNDS_LEFT);
-			cliprc.Xmax = parent->GetSize(SIZE_BOUNDS_RIGHT);
-			cliprc.Ymin = parent->GetSize(SIZE_BOUNDS_BOTTOM);
-			cliprc.Ymax = parent->GetSize(SIZE_BOUNDS_TOP);
-			break;
-			}
-		//no parent: use default
-	default:	memcpy(&cliprc, &lim, sizeof(fRECT));		break;
-		}
-	if(cliprc.Xmax < cliprc.Xmin) {
-		x = cliprc.Xmax;	cliprc.Xmax = cliprc.Xmin;	cliprc.Xmin = x;
-		}
-	if(cliprc.Ymax < cliprc.Ymin) {
-		y = cliprc.Ymax;	cliprc.Ymax = cliprc.Ymin;	cliprc.Ymin = y;
-		}
-	if(cliprc.Xmin == cliprc.Xmax || cliprc.Ymin == cliprc.Ymax) return;
-	if(pts) free(pts);
-	if(!(pts = (POINT *)malloc(sizeof(POINT)*200)))return;
-	switch(type & 0x07) {
-	case 1:		a = l2.fx;	b = l2.fy;	break;
-	case 2:		a = l3.fx;	b = l3.fy;	break;
-	case 3:		a = l4.fx;	b = l4.fy;	break;
-	case 4:		a = l5.fx;	b = l5.fy;	break;
-	default:	a = l1.fx;	b = l1.fy;	break;
-		}
-	x = cliprc.Xmin;	d = (cliprc.Xmax - cliprc.Xmin)/200.0;
-	for (cp = i = 0; i <= 200; i++){
-		dValid = true;
-		switch(type & 0x700) {
-		case 0x100:					//logarithmic x
-			if(dValid = x > defs.min4log) x1 = log10(x);
-			break;
-		case 0x200:					//reciprocal x
-			if(dValid = fabs(x) > defs.min4log) x1 = 1.0/x;
-			break;
-		case 0x300:					//square root x
-			if(dValid = fabs(x) > defs.min4log) x1 = sqrt(x);
-			break;
-		default:	x1 = x;	break;		//linear x
-			}
-		y = a + b*x1;
-		if(dValid) switch(type & 0x7000) {
-		case 0x1000:				//logarithmic y
-			y = pow(10.0, y);
-			break;
-		case 0x2000:				//reciprocal y
-			if(dValid = fabs(y) >0.0001) y = 1.0/y;
-			break;
-		case 0x3000:				//square root y
-			if(dValid = fabs(y) >0.0001) y = y*y;
-			break;
-			}
-		if(dValid && y >= cliprc.Ymin && y <= cliprc.Ymax) {
-			pn.x = o->fx2ix(x);	pn.y = o->fy2iy(y);
-			AddToPolygon(&cp, pts, &pn);
-			}
-		x += d;
-		}
-	if(cp < 2) return;
-	o->SetLine(&LineDef);
-	o->oPolyline(pts, cp);
-	if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
-	i = 2*o->un2ix(LineDef.width);		//increase size of rectangle for marks
-	IncrementMinMaxRect(&rDims, i);
-}
-
-void
-RegLine::DoMark(anyOutput *o, bool mark)
-{
-	if(pts && cp && o){
-		if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
-		else if(parent) parent->Command(CMD_REDRAW, 0L, o);
-		}
-}
-
-bool
-RegLine::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	POINT p1;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
-				return false; 
-			if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
-			}
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_REGLINE;
-		return true;
-	case CMD_BOUNDS:
-		if(tmpl) {
-			memcpy(&lim, tmpl, sizeof(fRECT));
-			memcpy(&uclip, tmpl, sizeof(fRECT));
-			}
-		return true;
-	case CMD_AUTOSCALE:
-		if(nPoints < 2) return false;
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
-			((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
-			return true;
-			}
-		return false;
-		}
-	return false;
-}
-
-void
-RegLine::Recalc(lfPOINT *values, long n)
-{
-	double sx, sy, dx, dy, sxy, sxx, syy;
-	double a, b, k;
-	long ic;
-
-	sx = sy = 0.0;
-	if((nPoints = n)<2) return;
-	for(ic = 0; ic < n; ic++) {
-		sx += values[ic].fx;		sy += values[ic].fy;
-		}
-	mx = sx /((double)nPoints);	my = sy/((double)nPoints);
-	sxy = sxx = syy = 0.0;
-	for(ic = 0; ic < n; ic++) {
-		dx = mx - values[ic].fx;	dy = my - values[ic].fy;
-		sxx += (dx*dx);	syy += (dy*dy);	sxy += (dx*dy);
-		}
-	l1.fy = sxy / sxx;			l1.fx = my - (sxy / sxx) * mx;
-	b = sxy / syy;				a = mx - (sxy / syy) * my;
-	l2.fy = 1.0/b;				l2.fx = -a / b;
-	l3.fy = (l1.fy+l2.fy)/2.0;	l3.fx = (l1.fx+l2.fx)/2.0;
-	l4.fy = sy/sx;				l4.fx = 0.0;
-	if(l5.fx == 0.0 && l5.fx == 0.0){
-		l5.fy = l1.fy;				l5.fx = l1.fx;
-		}
-	//calculate distance point from line algorithm
-	//Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
-	//   Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
-	//   pp. 47-48; ISBN 0-12-286165-5
-	k = (sqrt(1.0/(1.0+l1.fy*l1.fy))+sqrt(1.0/(1.0+l2.fy*l2.fy)))/2.0;
-	b = sqrt(1.0/(k*k) -1.0);
-	l3.fy = l3.fy > 0.0 ? b : -b;
-	l3.fx = my - mx * l3.fy;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Calculate and display a statnard deviation (SD-) ellipse
-SDellipse::SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
-	GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	type = sel;
-	Id = GO_SDELLIPSE;
-	if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT))){
-		memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
-		rl = new RegLine(this, data, values, n, type);
-		}
-}
-
-SDellipse::SDellipse(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) FileIO(FILE_READ);
-}
-
-SDellipse::~SDellipse()
-{
-	if(val) free(val);
-	if(pts) free(pts);
-	if(!(type & 0x10000) && parent && rl && 
-		parent->Command(CMD_DROP_OBJECT, rl, 0L)) return;
-	if(rl) DeleteGO(rl);
-}
-
-void
-SDellipse::DoPlot(anyOutput *o)
-{
-	int i;
-	double a1, b1, a2, b2, fv, k1, k2, ss1, ss2, np, x, dx, si, csi;
-	lfPOINT fp, fip;
-	POINT p1, *tmppts;
-
-	if(!rl) return;
-	if(pts) free(pts);
-	if(!(pts = (POINT *)malloc(sizeof(POINT)*420)))return;
-	//get line data from regression line object
-	mx = rl->GetSize(SIZE_MX);		my = rl->GetSize(SIZE_MY);
-	a1 = rl->GetSize(SIZE_A);		b1 = rl->GetSize(SIZE_B);
-	b2 = -1.0/b1;	a2 = my - b2 * mx;
-	//calculate sine and cosine for back rotation
-	fv = sqrt(1.0+b1*b1);			si = b1/fv;			csi = 1.0/fv;
-	//calculate distance from line for each point and squared sum of distances
-	//Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
-	//   Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
-	//   pp. 47-48; ISBN 0-12-286165-5
-	k1 = sqrt(1.0/(1.0+b1*b1));			k2 = sqrt(1.0/(1.0+b2*b2));
-	// y = a + b*x;
-	ss1 = ss2 = 0.0;
-	for(i = 0; i < nPoints; i++) {
-		fv = (a1 + b1 * val[i].fx - val[i].fy) * k1;	ss1 += (fv*fv);
-		fv = (a2 + b2 * val[i].fx - val[i].fy) * k2;	ss2 += (fv*fv);
-		}
-	np = ((double)(nPoints-1));
-	//SD perpendicular and in direction of regression line
-	sd1 = sqrt(ss1 /= np);		sd2 = sqrt(ss2 /= np);
-	dx = sd2/100.0;
-	for(i = 0, cp = 0, x = -sd2; i < 2; i++) {
-		do {
-			fv = (x*x)/ss2;
-			fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1) : 0.0;
-			fv = i ? fv : -fv;
-			fp.fx = mx + x * csi - fv * si;
-			fp.fy = my + x * si + fv * csi;
-			switch(type & 0x700) {
-			case 0x100:					//logarithmic x
-				fp.fx = pow(10.0, fp.fx);
-				break;
-			case 0x200:					//reciprocal x
-				if(fabs(fp.fx) > defs.min4log) fp.fx = 1.0/fp.fx;
-				else fp.fx = 0.0;
-				break;
-			case 0x300:					//square root x
-				if(fabs(fp.fx) > defs.min4log) fp.fx = fp.fx*fp.fx;
-				else fp.fx = 0.0;
-				break;
-				}
-			switch(type & 0x7000) {
-			case 0x1000:				//logarithmic y
-				fp.fy = pow(10.0, fp.fy);
-				break;
-			case 0x2000:				//reciprocal y
-				if(fabs(fp.fy) > defs.min4log) fp.fy = 1.0/fp.fy;
-				else fp.fy = 0.0;
-				break;
-			case 0x3000:				//square root y
-				if(fabs(fp.fy) > defs.min4log) fp.fy = fp.fy*fp.fy;
-				else fp.fy = 0.0;
-				break;
-				}
-			o->fp2fip(&fp, &fip);	p1.x = iround(fip.fx);		p1.y = iround(fip.fy);
-			AddToPolygon(&cp, pts, &p1);
-			}while((x += dx) < sd2 && x > -sd2);
-		x = sd2;
-		dx *= -1.0;
-		}
-	o->SetLine(&LineDef);
-	if(cp > 2) {
-		AddToPolygon(&cp, pts, pts);		//close polygon
-		if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
-		SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-		for(i = 2; i < cp; i++) 
-			UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
-		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
-		IncrementMinMaxRect(&rDims, i);
-		o->oPolyline(pts, cp);
-		}
-	else {
-		free(pts);
-		cp = 0;
-		}
-	if(!(type & 0x10000))rl->DoPlot(o);
-}
-
-void
-SDellipse::DoMark(anyOutput *o, bool mark)
-{
-	if(pts && cp && o){
-		if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
-		else if(parent) parent->Command(CMD_REDRAW, 0L, o);
-		}
-}
-
-bool
-SDellipse::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	POINT p1;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!(type & 0x10000) && rl && rl->Command(cmd, tmpl, o)) return true;
-			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
-				return false; 
-			if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
-			}
-		break;
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_RMU:
-		if(!(type & 0x10000) && parent && rl && parent->Command(CMD_DROP_OBJECT, rl, o)){
-			rl = 0L;
-			return true;
-			}
-		return false;
-	case CMD_INIT:
-		if(rl) return rl->PropertyDlg();
-		break;
-	case CMD_DROP_OBJECT:
-		if(tmpl && ((GraphObj*)tmpl)->Id == GO_REGLINE && !rl) {
-			rl = (RegLine *)tmpl;
-			rl->parent = this;
-			return true;
-			}
-		return false;
-	case CMD_SET_DATAOBJ:
-		Id = GO_SDELLIPSE;
-		if(rl) rl->Command(cmd, tmpl, o);
-		return true;
-	case CMD_BOUNDS:
-		if(tmpl) {
-			if(rl) rl->Command(cmd, tmpl, o);
-			memcpy(&lim, tmpl, sizeof(fRECT));
-			}
-		return true;
-	case CMD_DELOBJ:
-		if(tmpl && tmpl == (void*)rl) {
-			Undo.ValInt(parent, &type, 0L);
-			type |= 0x10000;
-			if(parent) parent->Command(CMD_REDRAW, 0L, o);
-			return true;
-			}
-		break;
-	case CMD_AUTOSCALE:
-		if(nPoints < 2) return false;
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
-			((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-void
-SDellipse::Recalc(lfPOINT *values, long n)
-{
-	if(val) free(val);
-	if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT)))
-		memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
-	if(rl) rl->Recalc(values, n);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Error bars are simple graphic objects
-ErrorBar::ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int which,
-	int xc, int xr, int yc, int yr, int ec, int er):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	fPos.fx = x;		fPos.fy = y;
-	ferr = err;
-	type = which;
-	Id = GO_ERRBAR;
-	data = d;
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || ec >= 0 || er >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = ec;	ssRef[2].y = er;
-			cssRef = 3;
-			}
-		}
-	Command(CMD_AUTOSCALE, 0L, 0L);
-}
-
-ErrorBar::ErrorBar(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	type = ERRBAR_VSYM;
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-ErrorBar::~ErrorBar()
-{
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	if(ssRef) free(ssRef);		ssRef = 0L;
-	if(name) free(name);		name = 0L;
-}
-
-bool
-ErrorBar::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_ERRBAR: 
-		SizeBar = value;
-		return true;
-	case SIZE_ERRBAR_LINE:
-		ErrLine.width = value;
-		return true;
-		}
-	return false;
-}
-
-bool
-ErrorBar::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_ERROR_LINE:
-		ErrLine.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-ErrorBar::DoPlot(anyOutput *target)
-{
-	int ie;
-
-	switch (type & 0x0ff) {
-	case ERRBAR_VSYM:
-	case ERRBAR_VUP:
-	case ERRBAR_VDOWN:
-		ie = target->un2ix(SizeBar/2.0);
-		break;
-	default:
-		ie = target->un2iy(SizeBar/2.0);
-		break;
-		}
-	target->SetLine(&ErrLine);
-	switch(type) {
-	case ERRBAR_VSYM:
-		ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
-		ebpts[0].y = target->fy2iy(fPos.fy-ferr);
-		ebpts[4].y = ebpts[5].y = ebpts[1].y = target->fy2iy(fPos.fy+ferr);
-		if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
-		ebpts[4].x = ebpts[2].x = ebpts[0].x - ie;
-		ebpts[5].x = ebpts[3].x = ebpts[1].x + ie+1;
-		ebpts[2].y = ebpts[3].y = ebpts[0].y;
-		if(ebpts[3].x > ebpts[2].x) {
-			target->oSolidLine(ebpts+2);
-			target->oSolidLine(ebpts+4);
-			}
-		rDims.left =  ebpts[2].x;		rDims.right = ebpts[3].x;
-		rDims.top = ebpts[0].y;			rDims.bottom = ebpts[1].y;
-		break;
-	case ERRBAR_VUP:
-	case ERRBAR_VDOWN:
-		ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
-		ebpts[0].y = target->fy2iy(fPos.fy);
-		ebpts[2].y = ebpts[3].y = ebpts[1].y = 
-			target->fy2iy(type == ERRBAR_VUP ? fPos.fy+ferr : fPos.fy-ferr);
-		if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
-		ebpts[2].x = ebpts[0].x - ie;
-		ebpts[3].x = ebpts[1].x + ie+1;
-		if(ebpts[3].x > ebpts[2].x) target->oSolidLine(ebpts+2);
-		rDims.left =  ebpts[2].x;		rDims.right = ebpts[3].x;
-		rDims.top = ebpts[0].y;			rDims.bottom = ebpts[1].y;
-		break;
-	case ERRBAR_HSYM:
-		ebpts[2].x = ebpts[3].x = ebpts[0].x = target->fx2ix(fPos.fx-ferr);
-		ebpts[4].x = ebpts[5].x = ebpts[1].x = target->fx2ix(fPos.fx+ferr);
-		ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
-		if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
-		ebpts[2].y = ebpts[4].y = ebpts[0].y - ie;
-		ebpts[3].y = ebpts[5].y = ebpts[1].y + ie+1;
-		if(ebpts[3].y >ebpts[2].y) {
-			target->oSolidLine(ebpts+2);
-			target->oSolidLine(ebpts+4);
-			}
-		rDims.left =  ebpts[0].x;		rDims.right = ebpts[1].x;
-		rDims.top = ebpts[2].y;			rDims.bottom = ebpts[3].y;
-		break;
-	case ERRBAR_HLEFT:
-	case ERRBAR_HRIGHT:
-		ebpts[0].x = target->fx2ix(fPos.fx);
-		ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
-		ebpts[2].x = ebpts[3].x = ebpts[1].x = 
-			target->fx2ix(type == ERRBAR_HRIGHT ? fPos.fx+ferr : fPos.fx-ferr);
-		if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
-		ebpts[2].y = ebpts[0].y - ie;
-		ebpts[3].y = ebpts[1].y + ie+1;
-		if(ebpts[3].y > ebpts[2].y) target->oSolidLine(ebpts+2);
-		rDims.left =  ebpts[0].x;		rDims.right = ebpts[1].x;
-		rDims.top = ebpts[2].y;			rDims.bottom = ebpts[3].y;
-		break;
-		}
-	if(rDims.left > rDims.right) Swap(rDims.left, rDims.right);
-	if(rDims.top > rDims.bottom) Swap(rDims.top, rDims.bottom);
-	IncrementMinMaxRect(&rDims, 2);
-}
-
-void
-ErrorBar::DoMark(anyOutput *o, bool mark)
-{
-	int i;
-	LineDEF OldLine;
 
-	if(mark){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
-		i = 3*o->un2ix(ErrLine.width);		//increase size of rectangle for marks
-		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
-		ErrLine.width *= 5.0;				DoPlot(o);
-		ErrLine.width = OldLine.width;		ErrLine.color = OldLine.color ^ 0x00ffffffL;
-		DoPlot(o);							o->UpdateRect(&mrc, false);
-		memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubbles are graphic objects
+Bubble::Bubble(GraphObj *par, DataObj *d, double x, double y, double s, int which, 
+	FillDEF *fill, LineDEF *outline, int xc, int xr, int yc, int yr, int sc,
+	int sr):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	fPos.fx = x;	fPos.fy = y;	fs = s;
+	type = which;
+	if(fill) {
+		memcpy(&BubbleFill,fill, sizeof(FillDEF));
+		if(BubbleFill.hatch) memcpy(&BubbleFillLine, BubbleFill.hatch, sizeof(LineDEF));
 		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	bool bFound;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		bFound = false;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!IsInRect(&rDims, mev->x, mev->y) || CurrGO) return false; 
-			switch (type) {
-			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
-				if(mev->y >= (ebpts[0].y-2) && mev->y <= (ebpts[1].y+2)) bFound = true;
-				else if(mev->x >= (ebpts[2].x-2) && mev->x <= (ebpts[2].x+2)) bFound = true;
-				else if(type == ERRBAR_HSYM && mev->x >= (ebpts[4].x-2) &&
-					mev->x <= (ebpts[4].x + 2)) bFound = true;
-				break;
-			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
-				if(mev->x >= (ebpts[0].x-2) && mev->x <= (ebpts[1].x+2)) bFound = true;
-				else if(mev->y >= (ebpts[2].y-2) && mev->y <= (ebpts[2].y+2)) bFound = true;
-				else if(type == ERRBAR_VSYM && mev->y >= (ebpts[4].y-2) &&
-					mev->y <= (ebpts[4].y + 2)) bFound = true;
-				break;
-				}
-			if(bFound) o->ShowMark(this, MRK_GODRAW);
-			}
-	case CMD_SET_DATAOBJ:
-		Id = GO_ERRBAR;
-		data = (DataObj *) tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >2 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &ferr);
-			return true;
-			}
-		return false;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		switch(type) {
-			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
-				((Legend*)tmpl)->HasErr(&ErrLine, 1, name);
-				break;
-			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
-				((Legend*)tmpl)->HasErr(&ErrLine, 2, name);
-				break;
+	BubbleFill.hatch = &BubbleFillLine;
+	if(outline)memcpy(&BubbleLine, outline, sizeof(LineDEF));
+	Id = GO_BUBBLE;
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || sc >= 0 || sr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = sc;	ssRef[2].y = sr;
+			cssRef = 3;
 			}
-		break;
-	case CMD_ERRDESC:
-		if(name = (char*)realloc(name, strlen((char*)tmpl)+2)) strcpy(name, (char*)tmpl);
-		return true;
-	case CMD_ERR_TYPE:
-		if(tmpl) type = *((int*)tmpl);
-		return true;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			switch(type) {
-			case ERRBAR_VSYM:	
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr);
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr);		break;
-			case ERRBAR_VUP:	
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr);		break;
-			case ERRBAR_VDOWN:
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr);		break;
-			case ERRBAR_HSYM:
-				((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
-				((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy);		break;
-			case ERRBAR_HLEFT:
-				((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy);
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);				break;
-			case ERRBAR_HRIGHT:
-				((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
-				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);				break;
-				}
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// arrows to data points or with absolute coordinates
-Arrow::Arrow(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
-	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2, int yc2, int yr2):
-	GraphObj(par, d)
-{
-	double dx, dy;
-
-	FileIO(INIT_VARS);
-	memcpy(&pos1, &fp1, sizeof(lfPOINT));
-	memcpy(&pos2, &fp2, sizeof(lfPOINT));
-	type = which;
-	if(type & ARROW_UNITS) {
-		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-		pos1.fx -= dx;	pos1.fy -= dy;			pos2.fx -= dx;	pos2.fy -= dy;
-		}
-	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
-		yc2 >= 0 || yr2 >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
-			ssRef[0].x = xc1;	ssRef[0].y = xr1;
-			ssRef[1].x = yc1;	ssRef[1].y = yr1;
-			ssRef[2].x = xc2;	ssRef[2].y = xr2;
-			ssRef[3].x = yc2;	ssRef[3].y = yr2;
-			cssRef = 4;
-			}
-		}
-	bModified = false;
-}
-
-Arrow::Arrow(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-Arrow::~Arrow()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-	if(bModified) Undo.InvalidGO(this);
-}
-
-double
-Arrow::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_XPOS:		return pos1.fx;
-	case SIZE_XPOS+1:	return pos2.fx;
-	case SIZE_YPOS:		return pos1.fy;
-	case SIZE_YPOS+1:	return pos2.fy;
-	case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
-	case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
-		if(parent) return parent->GetSize(select);
-		break;
-		}
-	return 0.0;
-}
-
-bool
-Arrow::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_ARROW_LINE:		LineDef.width = value;		return true;
-	case SIZE_ARROW_CAPWIDTH:	cw = value;					return true;
-	case SIZE_ARROW_CAPLENGTH:	cl = value;					return true;
-	case SIZE_XPOS:				pos1.fx = value;			return true;
-	case SIZE_XPOS+1:			pos2.fx = value;			return true;
-	case SIZE_YPOS:				pos1.fy = value;			return true;
-	case SIZE_YPOS+1:			pos2.fy = value;			return true;
-		}
-	return false;
-}
-
-bool
-Arrow::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_ARROW:
-		LineDef.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-Arrow::DoPlot(anyOutput *o)
-{
-	double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
-
-	if(!o || !parent) return;
-	if(type & ARROW_UNITS) {
-		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
-		fix1 = o->co2fix(pos1.fx+dx);	fix2 = o->co2fix(pos2.fx+dx);
-		fiy1 = o->co2fiy(pos1.fy+dy);	fiy2 = o->co2fiy(pos2.fy+dy);
-		}
-	else {
-		fix1 = o->fx2fix(pos1.fx);		fix2 = o->fx2fix(pos2.fx);
-		fiy1 = o->fy2fiy(pos1.fy);		fiy2 = o->fy2fiy(pos2.fy);
-		}
-	if(fix1 == fix2 && fiy1 == fiy2) return;	//zero length
-	//draw arrow line
-	pts[0].x = iround(fix1);		pts[1].x = iround(fix2);
-	pts[0].y = iround(fiy1);		pts[1].y = iround(fiy2);
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	//calculate sine and cosine for cap
-	si = fiy1-fiy2;
-	tmp = fix2 - fix1;
-	si = si/sqrt(si*si + tmp*tmp);
-	csi = fix2-fix1;
-	tmp = fiy2 - fiy1;
-	csi = csi/sqrt(csi*csi + tmp*tmp);
-	//draw cap
-	pts[2].x = pts[1].x - o->un2ix(csi*cl + si*cw/2.0);
-	pts[2].y = pts[1].y + o->un2iy(si*cl - csi*cw/2.0);
-	pts[3].x = pts[1].x;		pts[3].y = pts[1].y;
-	pts[4].x = pts[1].x - o->un2ix(csi*cl - si*cw/2.0);
-	pts[4].y = pts[1].y + o->un2iy(si*cl + csi*cw/2.0);
-	switch(type & 0xff) {
-	case ARROW_NOCAP:
-		pts[2].x = pts[3].x = pts[4].x = pts[1].x;
-		pts[2].y = pts[3].y = pts[4].y = pts[1].y;
-		break;
-		}
-	UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
-	UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
-	IncrementMinMaxRect(&rDims, 3);
-	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
-	else Redraw(o);
-}
-
-void
-Arrow::DoMark(anyOutput *o, bool mark)
-{
-	LineDEF OldLine;
-
-	if(type & ARROW_UNITS) {
-		if(!dh1) dh1 = new dragHandle(this, DH_12);
-		if(!dh2) dh2 = new dragHandle(this, DH_22);
-		}
-	else {
-		if (dh1) DeleteGO(dh1);		if (dh2) DeleteGO(dh2);
-		dh1 = dh2 = 0L;
-		}
-	memcpy(&OldLine, &LineDef, sizeof(LineDEF));
-	if(mark) {
-		LineDef.color = 0x00000000L;
-		LineDef.width = OldLine.width *3.0;
-		Redraw(o);
-		LineDef.width = OldLine.width;
-		LineDef.color = OldLine.color ^ 0x00ffffffL;
-		Redraw(o);
-		if(dh1) dh1->DoPlot(o);		if(dh2) dh2->DoPlot(o);
-		}
-	else if(parent){
-		LineDef.color = 0x00ffffffL;
-		LineDef.width = OldLine.width *3.0;
-		Redraw(o);
-		LineDef.width = OldLine.width;
-		LineDef.color = OldLine.color;
-		parent->DoPlot(o);
-		}
-	memcpy(&LineDef, &OldLine, sizeof(LineDEF));
-	o->UpdateRect(&rDims, false);
-}
-
-bool
-Arrow::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_SAVEPOS:
-		bModified = true;
-		Undo.SaveLFP(this, &pos1, 0L);
-		Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
-		return true;
-	case CMD_FLUSH:
-		if (dh1) DeleteGO(dh1);			dh1 = 0L;
-		if (dh2) DeleteGO(dh2);			dh2 = 0L;
-		if(ssRef) free(ssRef);			ssRef = 0L;
-		if(name) free(name);			name = 0L;
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-		if(!CurrGO && ObjThere(mev->x, mev->y)){
-			o->ShowMark(this, MRK_GODRAW);
-			return true;
-			}
-		}
-		break;
-	case CMD_ARROW_ORG:
-		memcpy(&pos1, tmpl, sizeof(lfPOINT));
-		if(ssRef && cssRef >3) 
-			ssRef[0].x = ssRef[0].y = ssRef[1].x = ssRef[1].y = -1;
-		return true;
-	case CMD_ARROW_TYPE:
-		if(tmpl) {
-			type &= ~0xff;		type |= (*((int*)tmpl));
-			return true;
-			}
-		return false;
-	case CMD_SET_DATAOBJ:
-		Id = GO_ARROW;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >3 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
-			((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
-			return true;
-			}
-		break;
-	case CMD_MRK_DIRTY:			//from Undo ?
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_MOVE:
-		bModified = true;
-	case CMD_UNDO_MOVE:
-		if(type & ARROW_UNITS) {
-			if(cmd == CMD_MOVE) Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-			pos1.fx += ((lfPOINT*)tmpl)[0].fx;	pos1.fy += ((lfPOINT*)tmpl)[0].fy;
-			pos2.fx += ((lfPOINT*)tmpl)[0].fx;	pos2.fy += ((lfPOINT*)tmpl)[0].fy;
-			if(o){
-				o->StartPage();		parent->DoPlot(o);		o->EndPage();
-				}
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-void
-Arrow::Redraw(anyOutput *o)
-{
-	FillDEF FillCap;
-
-	o->SetLine(&LineDef);
-	o->oSolidLine(pts);
-	switch(type & 0xff) {
-	case ARROW_NOCAP:
-		break;
-	case ARROW_LINE:
-		o->oSolidLine(pts+2);
-		o->oSolidLine(pts+3);
-		break;
-	case ARROW_TRIANGLE:
-		FillCap.type = FILL_NONE;
-		FillCap.color = LineDef.color;
-		FillCap.scale = 1.0f;
-		FillCap.hatch = 0L;
-		o->SetFill(&FillCap);
-		o->oPolygon(pts+2, 3);
-		break;
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// universal boxes
-Box::Box(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
-	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
-		int yc2, int yr2):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	memcpy(&pos1, &fp1, sizeof(lfPOINT));
-	memcpy(&pos2, &fp2, sizeof(lfPOINT));
-	type = which;
-	Id = GO_BOX;
-	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
-		yc2 >= 0 || yr2 >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
-			ssRef[0].x = xc1;	ssRef[0].y = xr1;
-			ssRef[1].x = yc1;	ssRef[1].y = yr1;
-			ssRef[2].x = xc2;	ssRef[2].y = xr2;
-			ssRef[3].x = yc2;	ssRef[3].y = yr2;
-			cssRef = 4;
-			}
-		}
-}
-
-Box::Box(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-Box::~Box()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-double
-Box::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_XPOS:
-		return (pos1.fx + pos2.fx)/2.0;
-	case SIZE_YPOS:
-		return (pos1.fy + pos2.fy)/2.0;
-		}
-	return 1.0;
-}
-
-bool
-Box::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_BOX_LINE:		Outline.width = value;		return true;
-	case SIZE_BOX:			size = value;				return true;
-	case SIZE_XPOS:			pos1.fx = value;			return true;
-	case SIZE_XPOS+1:		pos2.fx = value;			return true;
-	case SIZE_YPOS:			pos1.fy = value;			return true;
-	case SIZE_YPOS+1:		pos2.fy = value;			return true;
-		}
-	return false;
-}
-
-bool
-Box::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_BOX_LINE:
-		Outline.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-Box::DoPlot(anyOutput *o)
-{
-	double si, csi, tmp, fix1, fiy1, fix2, fiy2, fsize, dx, dy;
-
-	if(!parent || !o || size <= 0.001) return;
-	o->SetLine(&Outline);
-	o->SetFill(&Fill);
-	//calculate coordinates
-	fix1 = o->fx2fix(pos1.fx);	fix2 = o->fx2fix(pos2.fx);
-	fiy1 = o->fy2fiy(pos1.fy);	fiy2 = o->fy2fiy(pos2.fy);
-	//calculate sine and cosine
-	si = fiy1-fiy2;
-	tmp = fix2 - fix1;
-	si = si/sqrt(si*si + tmp*tmp);
-	csi = fix2-fix1;
-	tmp = fiy2 - fiy1;
-	csi = csi/sqrt(csi*csi + tmp*tmp);
-	if(type & BAR_WIDTHDATA) {			//use e.g. for density distribution
-		dx = si * size;					dy = csi * size;
-		pts[0].x = o->fx2ix(pos1.fx + dx);	pts[1].x = o->fx2ix(pos2.fx + dx);
-		pts[2].x = o->fx2ix(pos2.fx - dx);	pts[3].x = o->fx2ix(pos1.fx - dx);
-		pts[0].y = o->fy2iy(pos1.fy + dy);	pts[1].y = o->fy2iy(pos2.fy + dy);
-		pts[2].y = o->fy2iy(pos2.fy - dy);	pts[3].y = o->fy2iy(pos1.fy - dy);
-		}
-	else if(type & BAR_RELWIDTH) {
-		if(!parent || (pos1.fy == pos2.fy && pos1.fx == pos2.fx)) return;
-		fsize = parent->GetSize(pos1.fy == pos2.fy ? SIZE_BOXMINY : SIZE_BOXMINX);
-		fsize = fsize * size /200.0;
-		dx = si * fsize;					dy = csi * fsize;
-		pts[0].x = o->fx2ix(pos1.fx + dx);	pts[1].x = o->fx2ix(pos2.fx + dx);
-		pts[2].x = o->fx2ix(pos2.fx - dx);	pts[3].x = o->fx2ix(pos1.fx - dx);
-		pts[0].y = o->fy2iy(pos1.fy + dy);	pts[1].y = o->fy2iy(pos2.fy + dy);
-		pts[2].y = o->fy2iy(pos2.fy - dy);	pts[3].y = o->fy2iy(pos1.fy - dy);
-		}
-	else {
-		dx = o->un2fix(si*size/2.0);		dy = o->un2fiy(csi*size/2.0);
-		pts[0].x = iround(fix1 + dx);	pts[1].x = iround(fix2 + dx);
-		pts[2].x = iround(fix2 - dx);	pts[3].x = iround(fix1 - dx);
-		pts[0].y = iround(fiy1 + dy);	pts[1].y = iround(fiy2 + dy);
-		pts[2].y = iround(fiy2 - dy);	pts[3].y = iround(fiy1 - dy);
-		}
-	pts[4].x = pts[0].x;		pts[4].y = pts[0].y;	//close polygon
-	if(pts[0].x == pts[1].x){
-		o->oRectangle(pts[3].x, pts[3].y, pts[1].x, pts[1].y, name);
-		}
-	else {
-		o->oPolygon(pts, 5);
-		}
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[2].x, pts[2].y);
-	UpdateMinMaxRect(&rDims, pts[1].x, pts[1].y);
-	UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
-}
-
-void
-Box::DoMark(anyOutput *o, bool mark)
-{
-	InvertPolygon(pts, 5, &Outline, &Fill, &rDims, o, mark);
-}
-
-bool
-Box::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	POINT p;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name)free(name);			name = 0L;
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Outline, &Fill);
-		break;
-	case CMD_MRK_DIRTY:				case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
-					o->ShowMark(CurrGO = this, MRK_GODRAW);
-					return true;
-					}
-				else {
-					p.x = mev->x;		p.y = mev->y;
-					if(IsInPolygon(&p, pts, 5)) {
-						o->ShowMark(CurrGO = this, MRK_GODRAW);
-						return true;
-						}
-					}
-				}
-			break;
-			}
-		return false;
-	case CMD_SET_DATAOBJ:
-		Id = GO_BOX;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >3 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
-			return true;
-			}
-		return false;
-	case CMD_BOX_TYPE:
-		if(tmpl)type = *((int*)tmpl);
-		return true;
-	case CMD_BOX_FILL:
-		if(tmpl) {
-			memcpy(&Fill, tmpl, sizeof(FillDEF));
-			if(Fill.hatch) memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
-			Fill.hatch = &Hatchline;
-			return true;
-			}
-		break;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			if(type & BAR_WIDTHDATA) {
-				if(pos1.fy != pos2.fy) {
-					((Plot*)parent)->CheckBounds(pos1.fx+size, pos1.fy);
-					((Plot*)parent)->CheckBounds(pos2.fx-size, pos2.fy);
-					}
-				else {
-					((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy+size);
-					((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy-size);
-					}
-				}
-			else {
-				((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
-				((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
-				if(parent && (type & BAR_RELWIDTH)) {
-					if(pos1.fy == pos2.fy) {
-						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy + parent->GetSize(SIZE_BOXMINY));
-						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy - parent->GetSize(SIZE_BOXMINY));
-						}
-					else if(pos1.fx == pos2.fx) {
-						((Plot*)parent)->CheckBounds(pos2.fx + parent->GetSize(SIZE_BOXMINX), pos2.fy);
-						((Plot*)parent)->CheckBounds(pos2.fx - parent->GetSize(SIZE_BOXMINX), pos2.fy);
-						}
-					}
-				}
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// whisker 
-Whisker::Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
-	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
-	int yc2, int yr2):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	memcpy(&pos1, &fp1, sizeof(lfPOINT));
-	memcpy(&pos2, &fp2, sizeof(lfPOINT));
-	type = which;
-	Id = GO_WHISKER;
-	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
-		yc2 >= 0 || yr2 >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
-			ssRef[0].x = xc1;	ssRef[0].y = xr1;
-			ssRef[1].x = yc1;	ssRef[1].y = yr1;
-			ssRef[2].x = xc2;	ssRef[2].y = xr2;
-			ssRef[3].x = yc2;	ssRef[3].y = yr2;
-			cssRef = 4;
-			}
-		}
-	Command(CMD_AUTOSCALE, 0L, 0L);
-}
-
-Whisker::Whisker(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
+		}
 }
 
-Whisker::~Whisker()
+Bubble::Bubble(int src):GraphObj(0L, 0L)
 {
-	if(mo) DelBitmapClass(mo);	mo = 0L;
-	if(ssRef) free(ssRef);		ssRef = 0L;
-	if(name) free(name);		name = 0L;
-}
-
-bool
-Whisker::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_WHISKER: 
-		size = value;
-		return true;
-	case SIZE_WHISKER_LINE:
-		LineDef.width = value;
-		return true;
-		}
-	return false;
-}
-
-bool
-Whisker::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_WHISKER:
-		LineDef.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-Whisker::DoPlot(anyOutput *o)
-{
-	double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
-	int i;
-
-	fix1 = o->fx2fix(pos1.fx);	fix2 = o->fx2fix(pos2.fx);
-	fiy1 = o->fy2fiy(pos1.fy);	fiy2 = o->fy2fiy(pos2.fy);
-	if(fix1 == fix2 && fiy1 == fiy2) return;	//zero length
-	pts[2].x = iround(fix1);		pts[3].x = iround(fix2);
-	pts[2].y = iround(fiy1);		pts[3].y = iround(fiy2);
-	//calculate sine and cosine
-	si = fiy1-fiy2;
-	tmp = fix2 - fix1;
-	si = si/sqrt(si*si + tmp*tmp);
-	csi = fix2-fix1;
-	tmp = fiy2 - fiy1;
-	csi = csi/sqrt(csi*csi + tmp*tmp);
-	dx = o->un2fix(si*size/2.0);
-	dy = o->un2fiy(csi*size/2.0);
-	//calc cap
-	pts[0].x = iround(fix1 - dx);	pts[4].x = iround(fix2 - dx);
-	pts[0].y = iround(fiy1 - dy);	pts[4].y = iround(fiy2 - dy);
-	pts[1].x = iround(fix1 + dx);	pts[5].x = iround(fix2 + dx);
-	pts[1].y = iround(fiy1 + dy);	pts[5].y = iround(fiy2 + dy);
-	//draw whisker
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
-	UpdateMinMaxRect(&rDims, pts[5].x, pts[5].y);
-	IncrementMinMaxRect(&rDims, 3+(o->un2ix(LineDef.width)<<1));
-	o->SetLine(&LineDef);
-	switch(type & 0x0f) {
-	case 2:
-		pts[4].x = pts[3].x;	pts[4].y = pts[3].y;
-		pts[1].x = pts[2].x;	pts[1].y = pts[2].y;
-	case 3:
-		if((type & 0x0f) == 3){
-			pts[5].x = pts[3].x;	pts[5].y = pts[3].y;
-			pts[0].x = pts[2].x;	pts[0].y = pts[2].y;
-			}
-	case 0:
-		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
-		break;
-	case 1:
-		pts[4].x = pts[5].x = pts[3].x;		pts[4].y = pts[5].y = pts[3].y;
-		pts[1].x = pts[0].x = pts[2].x;		pts[1].y = pts[0].y = pts[2].y;
-		o->oSolidLine(pts+2);
-		break;
-		}
-}
-
-void
-Whisker::DoMark(anyOutput *o, bool mark)
-{
-	int i;
-	LineDEF OldLine;
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
 
-	if(mark){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
-		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
-		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
-		LineDef.width *= 5.0;				DoPlot(o);
-		LineDef.width = OldLine.width;		LineDef.color = OldLine.color ^ 0x00ffffffL;
-		DoPlot(o);							o->UpdateRect(&mrc, false);
-		memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+Bubble::~Bubble()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+void
+Bubble::DoPlot(anyOutput *o)
+{
+	int x1, y1, x2, y2, ix, iy, tmp;
+	double fix, fiy;
+
+	o->SetLine(&BubbleLine);
+	o->SetFill(&BubbleFill);
+	switch(type & 0x0f0) {
+	case BUBBLE_UNITS:
+		fix = o->un2fix(fs);		fiy = o->un2fiy(fs);
+		break;
+	case BUBBLE_XAXIS:
+		fix = (o->fx2fix(fPos.fx+fs) - o->fx2fix(fPos.fx-fs))/2.0;
+		fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f));	//x and y resolution different ?
+		break;
+	case BUBBLE_YAXIS:
+		fix = (o->fy2fiy(fPos.fy-fs) - o->fy2fiy(fPos.fy+fs))/2.0;
+		fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f));	//x and y resolution different ?
+		break;
 		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-Whisker::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				if(IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y) ||
-					IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
-					IsCloseToLine(&pts[4], &pts[5], mev->x, mev->y)) {
-						o->ShowMark(this, MRK_GODRAW);
-						return true;
-						}
-				}
-			break;
-			}
-		return false;
-	case CMD_ERRDESC:
-		if(name = (char*)realloc(name, strlen((char*)tmpl)+2)) strcpy(name, (char*)tmpl);
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		switch(type & 0x0f) {
-		case 1:		((Legend*)tmpl)->HasErr(&LineDef, 5, name);		break;
-		case 2:		((Legend*)tmpl)->HasErr(&LineDef, 4, name);		break;
-		case 3:		((Legend*)tmpl)->HasErr(&LineDef, 3, name);		break;
-		default:
-			if((rDims.right - rDims.left) < (rDims.bottom - rDims.top))
-				((Legend*)tmpl)->HasErr(&LineDef, 1, name);
-			else ((Legend*)tmpl)->HasErr(&LineDef, 2, name);
-			break;
+	fix = fix < 0.0 ? -fix : fix;							//sign must be positive
+	fiy = fiy < 0.0 ? -fiy : fiy;
+	rDims.left = rDims.right = iround(o->fx2fix(fPos.fx));
+	rDims.top = rDims.bottom = iround(o->fy2fiy(fPos.fy));
+	switch(type & 0x00f) {
+	case BUBBLE_CIRCLE:
+		ix = (int)(fix/2.0);			iy = (int)(fiy/2.0);
+		tmp = iround(o->fx2fix(fPos.fx));		x1 = tmp - ix;		x2 = tmp + ix;
+		tmp = iround(o->fy2fiy(fPos.fy));		y1 = tmp - iy;		y2 = tmp + iy;
+		o->oCircle(x1, y1, x2, y2, name);
+		UpdateMinMaxRect(&rDims, x1, y1);	UpdateMinMaxRect(&rDims, x2, y2);
+		break;
+	case BUBBLE_SQUARE:
+		if((type & 0xf00) == BUBBLE_CIRCUM) {
+			ix = iround(fix*.392699081);		iy = iround(fiy*.392699081);
+			}
+		else if((type & 0xf00) == BUBBLE_AREA) {
+			ix = iround(fix*.443113462);		iy = iround(fiy*.443113462);
 			}
+		else {
+			ix = iround(fix*.353553391);		iy = iround(fiy*.353553391);
+			}
+		tmp = iround(o->fx2fix(fPos.fx));		x1 = tmp - ix;		x2 = tmp + ix;
+		tmp = iround(o->fy2fiy(fPos.fy));		y1 = tmp - iy;		y2 = tmp + iy;
+		o->oRectangle(x1, y1, x2, y2, name);
+		UpdateMinMaxRect(&rDims, x1, y1);	UpdateMinMaxRect(&rDims, x2, y2);
 		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_WHISKER;		data = (DataObj *)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >3 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
-			((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
-			return true;
-			}
-		break;
-	case CMD_WHISKER_STYLE:
-		if(tmpl) type = *((int*)tmpl);
-		return true;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// drop line 
-DropLine::DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc, 
-	int xr, int yc, int yr):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	fPos.fx = x;
-	fPos.fy = y;
-	type = which;
-	Id = GO_DROPLINE;
-	if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			cssRef = 2;
-			}
-		}
-	bModified = false;
-}
-
-DropLine::DropLine(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-DropLine::~DropLine()
-{
-	if(bModified) Undo.InvalidGO(this);
-	if(ssRef) free(ssRef);		ssRef = 0L;
-}
-
-void
-DropLine::DoPlot(anyOutput *o)
-{
-	int tmp;
-
-	o->RLP.fp = 0.0f;		//reset line pattern start
-	if(parent) {
-		pts[0].x = pts[1].x = pts[2].x = pts[3].x = o->fx2ix(fPos.fx);
-		pts[0].y = pts[1].y = pts[2].y = pts[3].y = o->fy2iy(fPos.fy);
-		if(type & DL_LEFT) {
-			tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_LEFT));
-			if(tmp < pts[0].x) pts[0].x = tmp;
-			if(tmp > pts[1].x) pts[1].x = tmp;
-			}
-		if(type & DL_RIGHT) {
-			tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_RIGHT));
-			if(tmp < pts[0].x) pts[0].x = tmp;
-			if(tmp > pts[1].x) pts[1].x = tmp;
-			}
-		if(type & DL_YAXIS) {
-			tmp = iround(parent->GetSize(SIZE_YAXISX));
-			if(tmp < pts[0].x) pts[0].x = tmp;
-			if(tmp > pts[1].x) pts[1].x = tmp;
-			}
-		if(type & DL_TOP) {
-			tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_TOP));
-			if(tmp < pts[2].y) pts[2].y = tmp;
-			if(tmp > pts[3].y) pts[3].y = tmp;
-			}
-		if(type & DL_BOTTOM) {
-			tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_BOTTOM));
-			if(tmp < pts[2].y) pts[2].y = tmp;
-			if(tmp > pts[3].y) pts[3].y = tmp;
-			}
-		if(type & DL_XAXIS) {
-			tmp = iround(parent->GetSize(SIZE_XAXISY));
-			if(tmp < pts[2].y) pts[2].y = tmp;
-			if(tmp > pts[3].y) pts[3].y = tmp;
-			}
-		SetMinMaxRect(&rDims, pts[0].x, pts[2].y, pts[1].x, pts[3].y);
-		IncrementMinMaxRect(&rDims, 3);
-		o->SetLine(&LineDef);
-		o->oPolyline(pts, 2);
-		o->oPolyline(pts+2, 2);
-		}
-}
-
-void
-DropLine::DoMark(anyOutput *o, bool mark)
-{
-
-	InvertLine(pts, 2, &LineDef, 0L, o, mark);
-	InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
-}
-
-bool
-DropLine::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				if(IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
-					IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y)) {
-					o->ShowMark(this, MRK_GODRAW);
-					return true;
-					}
-				}
-			break;
-			}
-		return false;
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_DL_LINE:
-		if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
-		return true;
-	case CMD_DL_TYPE:
-		if(tmpl)type = *((int*)tmpl);
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_DROPLINE;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >1 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// define a spherical scanline used for clipping spheres
-sph_scanline::sph_scanline(POINT3D *center, int radius, bool bVert):GraphObj(0, 0)
-{
-	Id = GO_SPHSCANL;
-	rad = radius >= 0 ? radius : -radius;
-	memcpy(&p1, center, sizeof(POINT3D));	memcpy(&p2, center, sizeof(POINT3D));
-	memcpy(&cent, center, sizeof(POINT3D));
-	if(vert = bVert) {
-		p1.y -= rad;		p2.y += rad;
-		}
-	else {
-		p1.x -= rad;		p2.x += rad;
-		}
-	if(p1.x < 1) p1.x = 1;			if(p1.y < 1) p1.y = 1;
-	if(p2.x < p1.x) p2.x = p1.x;	if(p2.y < p1.y) p2.y = p1.y;
-	bValid1 = bValid2 = true;
-}
-
-bool
-sph_scanline::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	switch(cmd) {
-	case CMD_ADDTOLINE:
-		if(bValid1 && tmpl){
-			memcpy(&p2, tmpl, sizeof(POINT3D));
-			bValid2 = true;
-			return true;
-			}
-		break;
-	case CMD_STARTLINE:
-		if(!bValid1 && tmpl){
-			memcpy(&p1, tmpl, sizeof(POINT3D));
-			bValid1 = true;
-			}
-		break;
-		return true;
-		}
-	return false;
-}
-
-void
-sph_scanline::DoClip(GraphObj *co)
-{
-	POINT3D *pla;
-	int np, i;
-
-	if(!bValid1 || !bValid2) return;
-	switch(co->Id){
-	case GO_SPHERE:
-		bValid1 = bValid2 = false;
-		clip_sphline_sphere(this, &p1, &p2, &cent, rad, iround(co->GetSize(SIZE_RADIUS1)), 
-			iround(co->GetSize(SIZE_XPOS)), iround(co->GetSize(SIZE_YPOS)), 
-			iround(co->GetSize(SIZE_ZPOS)));
-		break;
-	case GO_PLANE:
-		for(i=0; ((plane*)co)->GetPolygon(&pla, &np, i); i++) {
-			bValid1 = bValid2 = false;
-			clip_sphline_plane(this, &p1, &p2, &cent, rad, pla, np, ((plane*)co)->GetVec());
-			}
-		break;
-		}
-}
-	
-bool
-sph_scanline::GetPoint(POINT *p, int sel)
-{
-	if(!bValid1 || !bValid2) {
-		p->x = p->y = 0;
-		return false;
-		}
-	switch(sel) {
-	case 1:
-		p->x = p1.x;	p->y = p1.y;
-		return true;
-	case 2:
-		p->x = p2.x;	p->y = p2.y;
-		return true;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Sphere: a symbol in three dimensional space
-Sphere::Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z, 
-	double r, int xc, int xr, int yc, int yr, int zc, int zr, int rc, int rr)
-	:GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	Id = GO_SPHERE;
-	fPos.fx = x;	fPos.fy = y;	fPos.fz = z;	size = r;
-	if(xc >=0 || xr >=0 || yc >=0 || yr >=0 || zc >=0 || zr >=0 || rc >=0 || rr >=0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = zc;	ssRef[2].y = zr;
-			ssRef[3].x = rc;	ssRef[3].y = rr;
-			cssRef = 4;
-			}
-		}
-	type = sel;
-	bModified = false;
-}
-
-Sphere::Sphere(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-Sphere::~Sphere()
-{
-	if(bModified) Undo.InvalidGO(this);
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-double
-Sphere::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_MIN_X:		return fip.fx - (double)rx;
-	case SIZE_MAX_X:		return fip.fx + (double)rx;
-	case SIZE_MIN_Y:		return fip.fy - (double)ry;
-	case SIZE_MAX_Y:		return fip.fy + (double)ry;
-	case SIZE_MIN_Z:		return fip.fz - (double)rx;
-	case SIZE_MAX_Z:		return fip.fz + (double)rx;
-	case SIZE_XPOS:			return fip.fx;
-	case SIZE_YPOS:			return fip.fy;
-	case SIZE_ZPOS:			return fip.fz;
-	case SIZE_RADIUS1:	case SIZE_RADIUS2:	return (double)rx;
-	case SIZE_XCENT:		return fPos.fx;
-	case SIZE_YCENT:		return fPos.fy;
-	case SIZE_ZCENT:		return fPos.fz;
-	case SIZE_DRADIUS:		return size;
-	case SIZE_SYMBOL:
-		if(!type) return size;
-		else return defs.GetSize(SIZE_SYMBOL);
-	case SIZE_SYM_LINE:		return Line.width;
-		}
-	return 0.0;
-}
-
-bool
-Sphere::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_SYMBOL:		size = value;			break;
-	case SIZE_SYM_LINE:		Line.width = value;		break;
-		}
-	return true;
-}
-
-DWORD
-Sphere::GetColor(int select)
+	case BUBBLE_UPTRIA:
+	case BUBBLE_DOWNTRIA:
+		if((type & 0xf00) == BUBBLE_CIRCUM) {
+			fix *= .523598775;		fiy *= .523598775;
+			}
+		else if((type & 0xf00) == BUBBLE_AREA) {
+			fix *= .673386843;		fiy *= .673386843;
+			}
+		else {
+			fix *=.433012702;		fiy *= .433012702;
+			}
+		ix =  iround(fix);		iy = iround(fiy*.57735);
+		tmp = iround(o->fx2fix(fPos.fx));
+		pts[0].x = pts[3].x = tmp - ix;		pts[1].x = tmp + ix;		pts[2].x = tmp;
+		tmp = iround(o->fy2fiy(fPos.fy));
+		if((type & 0x00f) == BUBBLE_UPTRIA) {
+			pts[0].y = pts[1].y = pts[3].y = tmp + iy;
+			pts[2].y = tmp - iround(fiy*1.1547);
+			}
+		else {
+			pts[0].y = pts[1].y = pts[3].y = tmp - iy;
+			pts[2].y = tmp + iround(fiy*1.1547);
+			}
+		o->oPolygon(pts, 4);
+		UpdateMinMaxRect(&rDims, pts[0].x, pts[0].y);
+		UpdateMinMaxRect(&rDims, pts[1].x, pts[2].y);
+		break;
+		}
+}
+
+void
+Bubble::DoMark(anyOutput *o, bool mark)
 {
-	switch(select) {
-	case COL_SYM_LINE:		return Line.color;
-	case COL_SYM_FILL:		return Fill.color;
-	default: return defs.Color(select);
+	if(mark) {
+		BubbleFillLine.color ^= 0x00ffffffL;
+		BubbleFill.color ^= 0x00ffffffL;
+		DoPlot(o);
+		BubbleFill.color ^= 0x00ffffffL;
+		BubbleFillLine.color ^= 0x00ffffffL;
+		}
+	else {
+		if(parent) parent->DoPlot(o);
+		else DoPlot(o);
 		}
+	o->UpdateRect(&rDims, false);
 }
-
-bool
-Sphere::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_SYM_LINE:		Line.color = col;		break;
-	case COL_SYM_FILL:		Fill.color = col;		break;
-		}
-	return true;
-}
-
-void
-Sphere::DoPlot(anyOutput *o)
-{
-	int i;
-
-	if(size <= 0.001 || !o) return;
-	if(!o->fvec2ivec(&fPos, &fip)) return;
-	bDrawDone = false;
-	if(scl){
-		for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
-		free(scl);
-		scl = 0L;	nscl = 0;
-		}
-	ix = iround(fip.fx);			iy = iround(fip.fy);
-	switch (type) {
-	case 1:
-		rx = ry = iround(size * 0.5 * o->ddx);		break;
-	case 2:
-		rx = ry = iround(size * 0.5 * o->ddy);		break;
-	case 3:
-		rx = ry = iround(size * 0.5 * o->ddz);		break;
-	default:
-		type = 0;
-	case 5:
-		rx = o->un2ix(size/2.0);	ry = o->un2iy(size/2.0);
-		break;
-		}
-	rDims.left = ix - rx;			rDims.right = ix + rx;
-	rDims.top = iy - ry;			rDims.bottom = iy + ry;
-	if(o->VPscale > 1.5 && (
-		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
-		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
-		bDrawDone = true;		return;
-		}
-	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
-	Command(CMD_REDRAW, 0L, o);
-}
-
-bool
-Sphere::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	int i;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name) free(name);		name = 0L;
-		if(scl){
-			for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
-			free(scl);
-			scl = 0L;	nscl = 0;
-			}
-		return true;
+
+bool 
+Bubble::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	bool bSelected = false;
+	unsigned long n, s;
+	POINT p;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(ssRef) free(ssRef);	ssRef = 0L;
+		if(name)free(name);		name = 0L;
+		return true;
+	case CMD_SCALE:
+		if(!tmpl) return false;
+		if((type & 0x0f0)== BUBBLE_UNITS) fs *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
 	case CMD_LEGEND:
 		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Line, &Fill);
-		break;
-	case CMD_SYM_FILL:
-		if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
-		return true;
-	case CMD_MRK_DIRTY:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_SPHERE;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_REDRAW:
-		//Note: this command is issued either by Undo (no output given) or
-		//  by Plot3D::DoPlot after sorting all objects (output specified)
-		if(!parent) return false;
-		if(!o) return parent->Command(cmd, tmpl, o);
-		if(bDrawDone) return false;
-		bDrawDone = true;
-		if(scl) DrawPG(o, 0);
-		else {
-			o->SetLine(&Line);				o->SetFill(&Fill);
-			if(Fill.type & FILL_LIGHT3D) o->oSphere(ix, iy, rx, 0L, 0, 0L);
-			else o->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
-			}
-		rx--;ry--;			//smaller marking rectangle
-		rDims.left = ix-rx-1;				rDims.right = ix+rx+1;
-		rDims.top = iy-ry-1;				rDims.bottom = iy+ry+1;
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				o->ShowMark(&rDims, MRK_INVERT);
-				CurrGO = this;
-				return true;
-				}
-			break;
-			}
-		break;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >1 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
-			if(cssRef >3) data->GetValue(ssRef[3].y, ssRef[3].x, &size);
-			return true;
-			}
-		return false;
-	case CMD_CLIP:
-		if(co = (GraphObj*)tmpl){
-			switch(co->Id) {
-			case GO_PLANE:
-			case GO_SPHERE:
-				DoClip(co);
-				break;
-				}
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-void
-Sphere::DoClip(GraphObj *co)
-{
-	RECT cliprc;
-	double d, d1;
-	POINT3D cscl;
-	int x, y, q, di, de, lim, cx, cy;
-	int i;
-
-	if(co && co->Id == GO_SPHERE) {
-		if(co->GetSize(SIZE_ZPOS) > fip.fz) return;
-		d1 = (d = co->GetSize(SIZE_XPOS) - fip.fx) * d;
-		d1 += (d = co->GetSize(SIZE_YPOS) - fip.fy) * d;
-		d1 = sqrt(d1 + (d = co->GetSize(SIZE_ZPOS) - fip.fz) * d);
-		if(d1 >= (co->GetSize(SIZE_RADIUS1) + rx))return;
-		}
-	else {
-		cliprc.left = iround(co->GetSize(SIZE_MIN_X));
-		cliprc.right = iround(co->GetSize(SIZE_MAX_X));
-		cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
-		cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
-		if(!OverlapRect(&rDims, &cliprc))return;
-		}
-	//use a list of horizontal scanlines created by a circular Bresenham's algorithm
-	//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
-	//   Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.; 
-	//   ISBN 0-12-288165-5 
-	if(!scl && (scl = (sph_scanline**)calloc(rx*7+2, sizeof(sph_scanline*)))) {
-		cscl.z = iround(fip.fz);			nscl = 0;
-		for(q = 0; q < 2; q++) {
-			x = lim = 0;	y = rx;		di = 2*(1-rx);
-			while( y >= lim) {
-				if(di < 0) {
-					de = 2*di + 2*y -1;
-					if(de > 0) {
-						x++;	y--;	di += (2*x -2*y +2);
-						}
-					else {
-						x++;	di += (2*x +1);
-						}
-					}
-				else {
-					de = 2*di -2*x -1;
-					if(de > 0) {
-						y--;	di += (-2*y +1);
-						}
-					else {
-						x++;	y--;	di += (2*x -2*y +2);
-						}
-					}
-				switch(q) {
-				case 0:
-					cy = rx - y;			cx = x;
-					break;
-				case 1:
-					cy = rx + x;			cx = y; 
-					break;
-					}
-				cscl.y = iround(fip.fy);		cscl.x = iround(fip.fx);
-				cscl.y = cscl.y - rx + cy;
-				if(cx > 1) scl[nscl++] = new sph_scanline(&cscl, cx, false);
-				}
-			}
-		}
-	if(!scl) return;
-	//do clip for every scanline
-	for(i = 0; i < nscl; i++) if(scl[i]) scl[i]->DoClip(co);
-}
-
-void
-Sphere::DrawPG(anyOutput *o, int start)
-{
-	POINT *pts, np;
-	long cp = 0;
-	int i = start, step = 1;
-
-	if(!o || !scl ||!nscl) return;
-	if((pts = (POINT*)calloc(nscl*2, sizeof(POINT)))) {
-		do {
-			if(scl[i]) {
-				if(step > 0) scl[i]->GetPoint(&np, 1);
-				else scl[i]->GetPoint(&np, 2);
-				if(np.x && np.y){
-					AddToPolygon(&cp, pts, &np);
-					}
-				else if(cp){
-					if(step > 0) DrawPG(o, i);			//split sphere
-					step = -1;
-					}
-				}
-			if(i == nscl && step > 0) step = -1;
-			else i += step;
-			}while(i > start);
-		}
-	o->SetLine(&Line);				o->SetFill(&Fill);
-	if(cp) o->oSphere(ix, iy, rx, pts, cp, name);
-	free(pts);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// plane: utility object to draw a flat plane in 3D space
-plane::plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line, 
-	  FillDEF *fill):GraphObj(par, d)
-{
-	int i;
-	long area;
-	double vlength, v1[3], v2[3], vp[3], area1;
-	bool v_valid = false;
-	
-	nli = n_ipts = n_lines = 0;
-	nldata = 0L;  ldata = 0L;	co = 0L;	lines = 0L;		PlaneVec = 0L;
-	Id = GO_PLANE;	totalArea = 0;
-	memcpy(&Line, line, sizeof(LineDEF));
-	memcpy(&Fill, fill, sizeof(FillDEF));
-	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
-	if(nPts > 2 && (ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
-		(ldata[0] = (POINT3D *)calloc(nPts+1, sizeof(POINT3D))) &&
-		(nldata = (int*)calloc(1, sizeof(int)))	&&
-		(ipts = (POINT*)calloc(nPts, sizeof(POINT)))){
-		for(i = 0; i < nPts; i++) {
-			ipts[i].x = ldata[0][i].x = iround(pts[i].fx);
-			ipts[i].y = ldata[0][i].y = iround(pts[i].fy);
-			ldata[0][i].z = iround(pts[i].fz);
-			}
-		nldata[0] = nPts;		nli = 1;	n_ipts = nPts;
-		xBounds.fx = xBounds.fy = pts[0].fx;	yBounds.fx = yBounds.fy = pts[0].fy;
-		zBounds.fx = zBounds.fy = pts[0].fz;
-		rDims.left = rDims.right = ipts[0].x;	rDims.top = rDims.bottom = ipts[0].y;
-		for(i = 1; i < nPts; i++){
-			UpdateMinMaxRect(&rDims, ipts[i].x, ipts[i].y);
-			if(pts[i].fx < xBounds.fx) xBounds.fx = pts[i].fx;
-			if(pts[i].fx > xBounds.fy) xBounds.fy = pts[i].fx;
-			if(pts[i].fy < yBounds.fx) yBounds.fx = pts[i].fy;
-			if(pts[i].fy > yBounds.fy) yBounds.fy = pts[i].fy;
-			if(pts[i].fz < zBounds.fx) zBounds.fx = pts[i].fz;
-			if(pts[i].fz > zBounds.fy) zBounds.fy = pts[i].fz;
-			}
-		//test if plane vertical
-		area1 = (xBounds.fx - xBounds.fy) * (yBounds.fx - yBounds.fy);
-		for(area = 0, i = 1; i < nPts; i++) {
-			area += (ipts[i].x - ipts[i-1].x) * ((ipts[i].y + ipts[i-1].y)>>1);
-			}
-		totalArea= area = abs(area);
-		area1 = area ? fabs(area1/area) : 101.0;
-		if(area < 100 && area1 > 100.0) {			//its small or vertical !
-			if(lines=(line_segment**)calloc(nPts, sizeof(line_segment*))){
-				for(i = 1; i < nPts; i++) {
-					lines[i-1] = new line_segment(par, d, line, &ldata[0][i-1], &ldata[0][i]);
-					}
-				n_lines = nPts-1;
-				}
-			}
-		else {					//for a visible plane get vector perpendicular to plane
-			for (i = 1; i < (nPts-1); i++) {
-				v1[0] = pts[i].fx - pts[i-1].fx;	v1[1] = pts[i].fy - pts[i-1].fy;
-				v1[2] = pts[i].fz - pts[i-1].fz;	v2[0] = pts[i+1].fx - pts[i].fx;
-				v2[1] = pts[i+1].fy - pts[i].fy;	v2[2] = pts[i+1].fz - pts[i].fz;
-				vp[0] = v1[1]*v2[2] - v1[2]*v2[1];	vp[1] = v1[2]*v2[0] - v1[0]*v2[2];
-				vp[2] = v1[0]*v2[1] - v1[1]*v2[0];
-				vlength = sqrt(vp[0]*vp[0]+vp[1]*vp[1]+vp[2]*vp[2]);
-				if(v_valid = (vlength > 100.0)) break;
-				}
-			if(v_valid && (PlaneVec = (double*)malloc(4 * sizeof(double)))) {
-				PlaneVec[0] = vp[0]/vlength;		PlaneVec[1] = vp[1]/vlength;
-				PlaneVec[2] = -vp[2]/vlength;
-				PlaneVec[3] = PlaneVec[0] * pts[i].fx + PlaneVec[1] * pts[i].fy - PlaneVec[2] * pts[i].fz;
-				}
-			}
-		}
-}
-
-plane::~plane() 
-{
-	int i;
-
-	if(ldata) {
-		for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
-		free(ldata);	ldata = 0L;		nli = 0;
-		}
-	if(lines) {
-		for(i = 0; i < n_lines; i++) if(lines[i]) delete(lines[i]);
-		free(lines);	lines = 0L;		n_lines = 0;
-		}
-	if(nldata) free(nldata);		nldata = 0L;
-	if(ipts) free(ipts);			ipts = 0L;
-	if(PlaneVec) free(PlaneVec);	PlaneVec = 0L;
-}
-
-double
-plane::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_MIN_X:		return xBounds.fx;
-	case SIZE_MAX_X:		return xBounds.fy;
-	case SIZE_MIN_Y:		return yBounds.fx;
-	case SIZE_MAX_Y:		return yBounds.fy;
-	case SIZE_MIN_Z:		return zBounds.fx;
-	case SIZE_MAX_Z:		return zBounds.fy;
-		}
-	return 0.0;
-}
-
-void
-plane::DoPlot(anyOutput *o)
-{
-	int i;
-
-	bDrawDone = bReqPoint = false;
-	if(Fill.type & FILL_LIGHT3D){
-		Fill.color = o->VecColor(PlaneVec, Fill.color2, Fill.color);
-		Fill.type &= ~FILL_LIGHT3D;
-		}
-	if(o->VPscale > 1.5 && (
-		//ignore objects outside the display ara
-		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
-		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
-		bDrawDone = true;		return;
-		}
-	if(lines) {
-		if(Line.width == 0.0) return;
-		//draw line segments for vertical plane
-		for(i = 0; i < n_lines; i++) if(lines[i]) lines[i]->DoPlot(o);
-		bDrawDone = true;		return;
-		}
-	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
-	Command(CMD_REDRAW, 0L, o);
-}
-
-void
-plane::DoMark(anyOutput *o, bool mark)
-{
-	FillDEF tmpfill;
-	LineDEF tmpline;
-
-	memcpy(&tmpfill, &Fill, sizeof(FillDEF));
-	memcpy(&tmpline, &Line, sizeof(LineDEF));
-	if(mark){
-		tmpfill.color ^= 0x00ffffffL;		tmpline.color ^= 0x00ffffffL;
-		}
-	o->SetLine(&tmpline);					o->SetFill(&tmpfill);
-	o->oPolygon(ipts, n_ipts);
-}
-
-bool 
-plane::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	POINT *pt;
-	POINT3D *ap;
-	int i, j;
-	
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		if(parent) return parent->Command(cmd, tmpl, o);
+		((Legend*)tmpl)->HasFill(&BubbleLine, &BubbleFill, 0L);
 		break;
-	case CMD_REDRAW:
-		if(bDrawDone) return false;
-		bDrawDone = true;
-		if(o && nldata){
-			if(Line.width == 0.0) Line.color = Fill.color;
-			o->SetLine(&Line);			o->SetFill(&Fill);
-			for(i = 0; i < nli; i++){
-				if(nldata[i] > 2 && (pt = (POINT*)malloc(nldata[i]*sizeof(POINT)))){
-					for(j = 0; j < nldata[i]; j++) {
-						pt[j].x = ldata[i][j].x;	pt[j].y = ldata[i][j].y;
-						}
-					o->oPolygon(pt, nldata[i]);
-					free(pt);
-					}
-				}
-			}
-		return true;
-	case CMD_STARTLINE:
-		if(ap = (POINT3D*)tmpl) {
-			if(ldata && nldata && nli) {
-				if(bReqPoint) {
-					Command(CMD_ADDTOLINE, &ReqPoint, o);
-					bReqPoint = false;
-					}
-				i = nli-1;			j = nldata[i]-1;
-				if(ldata[i][j].x == ap->x && ldata[i][j].y == ap->y && ldata[i][j].z == ap->z){
-					return true;
-					}
-				if(IsValidPG(ldata[i], nldata[i])) {
-					//close previous polygon first
-					if(ldata[i][0].x != ldata[i][j].x || ldata[i][0].y != ldata[i][j].y ||
-						ldata[i][0].z != ldata[i][j].z){
-						j++;
-						ldata[i][j].x = ldata[i][0].x;	ldata[i][j].y = ldata[i][0].y;
-						ldata[i][j].z = ldata[i][0].z;	nldata[i]++;
-						}
-					ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
-					ldata[nli] = (POINT3D*)malloc(sizeof(POINT3D)*2);
-					nldata = (int*)realloc(nldata, sizeof(int) * (nli+1));
-					}
-				else {					//drop incomplete or invalid polygon
-					nli--;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, p.x = mev->x, p.y = mev->y) && !CurrGO) {
+				switch(type & 0x00f) {
+				case BUBBLE_CIRCLE:
+					n = s = p.x - ((rDims.right+rDims.left)>>1);
+					s *= n;
+					n = p.y - ((rDims.bottom+rDims.top)>>1);
+					n = isqr(s += n*n) -2;
+					bSelected = ((unsigned)((rDims.right-rDims.left)>>1) > n);
+					break;
+				case BUBBLE_SQUARE:
+					bSelected = true;
+					break;
+				case BUBBLE_UPTRIA:
+				case BUBBLE_DOWNTRIA:
+					if(!(bSelected = IsInPolygon(&p, pts, 4)))
+						bSelected = IsCloseToPL(p, pts, 4);
+					break;
 					}
+				if(bSelected) o->ShowMark(this, MRK_GODRAW);
+				return bSelected;
 				}
-			else {
-				ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
-				ldata[nli = 0] = (POINT3D*)malloc(sizeof(POINT3D));
-				nldata = (int*)calloc(1, sizeof(int));
-				bReqPoint = false;
-				}
-			if(ldata && nldata) {
-				ldata[nli][0].x = ap->x;	ldata[nli][0].y = ap->y;
-				ldata[nli][0].z = ap->z;	nldata[nli++] = 1;
-				return true;
-				}
-			}
-		break;
-	case CMD_REQ_POINT:
-		if(ap = (POINT3D*)tmpl) {
-			ReqPoint.x = ap->x;		ReqPoint.y = ap->y;		ReqPoint.z = ap->z;
-			bReqPoint = true;
+			break;
 			}
-		return true;
-	case CMD_ADDTOLINE:
-		if((ap = (POINT3D*)tmpl) && ldata && nldata && nli) {
-			i= nli-1;	j=nldata[i]-1;
-			if((ldata[i][j].x == ap->x && ldata[i][j].y == ap->y) ||
-				(ldata[i][j].y == ap->y && ldata[i][j].z == ap->z)){
-				//probably nothing to add
-				ldata[i][j].x = ap->x;			ldata[i][j].y = ap->y;
-				return j>0 ? true : false;
-				}
-			ldata[i] = (POINT3D*)realloc(ldata[i], ((j=nldata[i])+2) * sizeof(POINT3D));
-			ldata[i][j].x = ap->x;			ldata[i][j].y = ap->y;
-			ldata[i][j].z = ap->z;			nldata[i]++;
-			return true;
-			}
-	case CMD_CLIP:
-		if(co = (GraphObj*)tmpl){
-			switch(co->Id) {
-			case GO_PLANE:
-				//Clip only planes which are drawn later
-				if(GetSize(SIZE_MIN_Z) < co->GetSize(SIZE_MIN_Z)) return false;
-				if(nli){
-					DoClip(co);
-					if(nli && ldata) {
-						i = nli-1;			j = nldata[i]-1;
-						//is last part valid ?
-						if(j < 2) {
-							free(ldata[i]);		ldata[i] = 0L;
-							nldata[i] = 0;
-							nli--;
-							}
-						//close last polygon
-						else if(ldata[i][0].x != ldata[i][j].x ||
-							ldata[i][0].y != ldata[i][j].y ||
-							ldata[i][0].z != ldata[i][j].z){
-							j++;
-							ldata[i][j].x = ldata[i][0].x;
-							ldata[i][j].y = ldata[i][0].y;
-							ldata[i][j].z = ldata[i][0].z;
-							nldata[i]++;
-							}
-						}
-					}
-				else xBounds.fx=xBounds.fy=yBounds.fx=yBounds.fy=zBounds.fx=zBounds.fy=0.0;
-				break;
-				}
-			}
-		break;
-		}
-	return false;
-}
-
-void * 
-plane::ObjThere(int x, int y)
-{
-	POINT p1;
-
-	if(bDrawDone && IsInRect(&rDims, p1.x = x, p1.y = y) &&
-		(IsInPolygon(&p1, ipts, n_ipts) || IsCloseToPL(p1, ipts, n_ipts))) return this;
-	return 0L;
-}
-
-bool
-plane::GetPolygon(POINT3D **pla, int *npt, int n)
-{
-	if(n < nli && ldata && ldata[n]) {
-		*pla = ldata[n];	*npt = nldata[n];
-		return true;
-		}
-	return false;
-}
-
-void
-plane::DoClip(GraphObj *co)
-{
-	RECT cliprc;
-	int o_nli, *o_nldata = 0L;
-	POINT3D **o_ldata = 0L;
-	POINT3D *tpg;
-	int i, j, tnpt;
-	bool is_valid = false;
-
-	//if two planes have the same parent it means they are part of one object
-	// do not clip!
-	if(co->parent == parent && co->Id == GO_PLANE) return;
-	if(co->Id == GO_PLANE && (parent->parent->Id == GO_GRID3D || parent->parent->Id == GO_RIBBON)
-		&& co->parent->parent == parent->parent) return;
-	cliprc.left = iround(co->GetSize(SIZE_MIN_X));
-	cliprc.right = iround(co->GetSize(SIZE_MAX_X));
-	cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
-	cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
-	if(OverlapRect(&rDims, &cliprc) && co != this) {
-		o_nli = nli;		nli = 0;
-		o_nldata = nldata;	nldata = 0L;
-		o_ldata = ldata;	ldata = 0L;
-		switch(co->Id) {
-		case GO_PLANE:
-			//clip all parts of this plane with all from another plane
-			for(i = 0; ((plane*)co)->GetPolygon(&tpg, &tnpt, i); i++){
-				for(j = 0; j < o_nli; j++) {
-					if(o_nldata[j] >2) clip_plane_plane(this, o_ldata[j], o_nldata[j], PlaneVec, 
-						tpg, tnpt, ((plane*)co)->GetVec(), ipts, n_ipts );
-					}
-				if(bReqPoint){
-					Command(CMD_ADDTOLINE, &ReqPoint, 0L);
-					bReqPoint = false;
-					}
-				if(nli) is_valid = true;
-				if(o_ldata) {
-					for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
-					free(o_ldata);
-					}
-				if(o_nldata) free(o_nldata);
-				o_nli = nli;		nli = 0;
-				o_nldata = nldata;	nldata = 0L;
-				o_ldata = ldata;	ldata = 0L;
-				if(!o_nli) {					//plane is completly hidden
-					return;
-					}
-				}
-			if(is_valid || i==0){
-				nli = o_nli;		o_nli = 0;
-				nldata = o_nldata;	o_nldata = 0L;
-				ldata = o_ldata;	o_ldata = 0L;
-				}
-			if(nli > 1) for(i = 1; i < nli; i++) {
-				if(nldata[i] > 3 && ldata[i][nldata[i]-1].x == ldata[i-1][0].x
-					&& ldata[i][nldata[i]-1].y == ldata[i-1][0].y) {
-					nldata[i]--;	//bad vis: ignore last point
-					}
-				}
-			break;
-		default:
-			nli = o_nli;		o_nli = 0;
-			nldata = o_nldata;	o_nldata = 0L;
-			ldata = o_ldata;	o_ldata = 0L;
-			break;
-			}
-		//check shape and recalc some values
-		if(is_valid && nli) {
-			xBounds.fx = xBounds.fy = ldata[0][0].x;	yBounds.fx = yBounds.fy = ldata[0][0].y;
-			zBounds.fx = zBounds.fy = ldata[0][0].z;
-			rDims.left = rDims.right = ldata[0][0].x;	rDims.top = rDims.bottom = ldata[0][0].y;
-			for(i = 0; i < nli; i++) if(nldata[i] > 2){
-				if(ldata[i][0].x != ldata[i][nldata[i]-1].x || ldata[i][0].y != ldata[i][nldata[i]-1].y
-					|| ldata[i][0].z != ldata[i][nldata[i]-1].z) {
-					ldata[i][nldata[i]].x = ldata[i][0].x;	ldata[i][nldata[i]].y = ldata[i][0].y;
-					ldata[i][nldata[i]].z = ldata[i][0].z;	nldata[i]++;
-					}
-				for(j = 0; j < (nldata[i]-1); j++) {
-					UpdateMinMaxRect(&rDims, ldata[i][j].x, ldata[i][j].y);
-					if(ldata[i][j].x < xBounds.fx) xBounds.fx = ldata[i][j].x;
-					if(ldata[i][j].x > xBounds.fy) xBounds.fy = ldata[i][j].x;
-					if(ldata[i][j].y < yBounds.fx) yBounds.fx = ldata[i][j].y;
-					if(ldata[i][j].y > yBounds.fy) yBounds.fy = ldata[i][j].y;
-					if(ldata[i][j].z < zBounds.fx) zBounds.fx = ldata[i][j].z;
-					if(ldata[i][j].z > zBounds.fy) zBounds.fy = ldata[i][j].z;
-					}
-				}
-			}
-		}
-	if(o_ldata) {
-		for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
-		free(o_ldata);
-		}
-	if(o_nldata) free(o_nldata);
-}
-
-bool
-plane::IsValidPG(POINT3D *pg, int npg)
-{
-	int i;
-	long area;
-
-	//a polygon must have more than 3 Points
-	if(npg < 3) return false;
-	//check for a reasonable size
-	for(area = 0, i = 1; i < npg; i++) {
-		area += (pg[i].x - pg[i-1].x) * ((pg[i].y + pg[i-1].y)>>1);
-		}
-	area += (pg[0].x - pg[i-1].x) * ((pg[0].y + pg[i-1].y)>>1);
-	area = abs(area);
-	if(area < 20) return false;
-	if(totalArea/area > 100) return false;
-	return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// a simple plane in three dimensional space
-Plane3D::Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt)
-	:GraphObj(par, da) 
-{
-	FileIO(INIT_VARS);
-	Id = GO_PLANE3D;
-	dt = (fPOINT3D*) memdup(pt, sizeof(fPOINT3D)*npt, 0L);
-	ndt = npt;
-}
-
-Plane3D::Plane3D(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-Plane3D::~Plane3D()
-{
-	if(dt) free(dt);	if(pts) free(pts);
-	dt = 0L;		ndt = 0L;
-	if(ipl) delete (ipl);	ipl = 0L;
-}
-
-bool
-Plane3D::SetSize(int select, double value)
-{
-	int i;
-
-	if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <=  SIZE_XPOS_LAST){
-		if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)ndt){
-			dt[i].fx = value;			return true;
-			}
-		}
-	else if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
-		if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)ndt){
-			dt[i].fy = value;			return true;
-			}
-		}
-	else if((select & 0xfff) >= SIZE_ZPOS && (select & 0xfff) <= SIZE_ZPOS_LAST){
-		if((i = select-SIZE_ZPOS) >=0 && i <= 200 && i < (int)ndt){
-			dt[i].fz = value;			return true;
-			}
-		}
-	else switch(select) {
-	case SIZE_SYM_LINE:
-		Line.width = value;
-		}
-	return false;
-}
-
-bool
-Plane3D::SetColor(int select, DWORD col)
-{
-	switch(select) {
-	case COL_POLYLINE:		Line.color = col;		return true;
-	case COL_POLYGON:		Fill.color = col;		return true;
-		}
-	return false;
-}
-
-void
-Plane3D::DoPlot(anyOutput *o)
-{
-	int i;
-
-	if(ipl) delete ipl;		ipl = 0L;
-	if(pts) free(pts);		pts = 0L;
-	o->ActualSize(&rDims);
-	rDims.left = rDims.right;	rDims.top = rDims.bottom;
-	rDims.right = rDims.bottom = 0;
-	if((pts = (fPOINT3D*)malloc(sizeof(fPOINT3D)*ndt))){
-		for(i = 0; i < ndt; i++) {
-			if(!o->fvec2ivec(&dt[i], &pts[i])){
-				free(pts);	pts = 0L; return;
-				}
-			UpdateMinMaxRect(&rDims, iround(pts[i].fx), iround(pts[i].fy));
-			}
-		if(ipl = new plane(this, data, pts, i, &Line, &Fill))ipl->DoPlot(o);
-		}
-	IncrementMinMaxRect(&rDims, o->un2ix(Line.width)+1);
-}
-
-void
-Plane3D::DoMark(anyOutput *o, bool mark)
-{
-	if(mark){
-		if(pts && ipl)ipl->DoMark(o, mark);
-		o->UpdateRect(&rDims, false);
-		}
-	else if(parent) parent->Command(CMD_REDRAW, 0L, o);
-}
-
-bool
-Plane3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i;
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_SET_DATAOBJ:
-		Id = GO_PLANE3D;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Line, &Fill);
-		break;
-	case CMD_MRK_DIRTY:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_SYM_FILL:
-		if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
-		return true;
-	case CMD_REDRAW:
-		//Note: this command is issued either by Undo (no output given) or
-		//  by Plot3D::DoPlot after sorting all objects (output specified)
-		if(!parent) return false;
-		if(!o) return parent->Command(cmd, tmpl, o);
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				if(ipl && ipl->ObjThere(mev->x, mev->y)){
-					o->ShowMark(CurrGO=this, MRK_GODRAW);
-					return true;
-					}
-				}
-			break;
-			}
-		break;
-	case CMD_PG_FILL:
-		if(tmpl) {
-			memcpy((void*)&Fill, tmpl, sizeof(FillDEF));
-			Fill.hatch = 0L;
-			}
-		break;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && dt) {
-			for(i = 0; i < ndt; i++)
-				((Plot*)parent)->CheckBounds3D(dt[i].fx, dt[i].fy, dt[i].fz);
-			return true;
-			}
-		break;
-	case CMD_SET_GO3D:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Brick: a bar in three dimensional space
-Brick::Brick(GraphObj *par, DataObj *da, double x, double y, double z, 
-		double d, double w, double h, DWORD flg, int xc, int xr, int yc,
-		int yr, int zc, int zr, int dc, int dr, int wc, int wr, int hc,
-		int hr):GraphObj(par, da)
-{
-	FileIO(INIT_VARS);
-	Id = GO_BRICK;
-	fPos.fx = x;	fPos.fy = y;	fPos.fz = z;
-	depth = d;		width = w;		height = h;
-	flags = flg;
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0 ||
-		dc >= 0 || dr >= 0 || wc >= 0 || wr >= 0 || hc >= 0 || hr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = zc;	ssRef[2].y = zr;
-			ssRef[3].x = dc;	ssRef[3].y = dr;
-			ssRef[4].x = wc;	ssRef[4].y = wr;
-			ssRef[5].x = hc;	ssRef[5].y = hr;
-			cssRef = 6;
-			}
-		}
-	bModified = false;
-}
-
-Brick::Brick(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-	
-Brick::~Brick()
-{
-	int i;
-
-	if(faces) {
-		for(i = 0; i < 6; i++) if(faces[i]) delete(faces[i]);
-		free(faces);
-		}
-	faces = 0L;
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	Command(CMD_FLUSH, 0L, 0L);
-	if(bModified) Undo.InvalidGO(this);
-}
-
-bool
-Brick::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_BAR_LINE:		Line.width = value;		return true;
-	case SIZE_BAR_BASE:		fPos.fy = value;		return true;
-	case SIZE_BAR:			width = value;			return true;
-	case SIZE_BAR_DEPTH:	depth = value;			return true;
-		}
-	return false;
-}
-
-bool
-Brick::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_BAR_LINE:		Line.color = col;		return true;
-	case COL_BAR_FILL:		Fill.color = col;		return true;
-		}
-	return false;
-}
-
-void
-Brick::DoPlot(anyOutput *o)
-{
-	fPOINT3D cpt[8], fip1, fip2, tmp, itmp, *pg;
-	plane *npl;
-	double dtmp;
-	int i;
-
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	if(!faces || !o || !o->fvec2ivec(&fPos, &fip1)) return;
-	if(!(pg = (fPOINT3D *)malloc(5*sizeof(fPOINT3D)))) return;
-	for(i = 0; i < 6; i++) {
-		if(faces[i]) delete(faces[i]);
-		faces[i] = 0L;
-		}
-	if(flags & 0x800L) {		//height is data
-		tmp.fx = fPos.fx;			tmp.fy = height;
-		tmp.fz = fPos.fz;			o->fvec2ivec(&tmp, &fip2);
-		}
-	else {						//height is units
-		tmp.fx = tmp.fz = 0.0;		tmp.fy = height;
-		o->uvec2ivec(&tmp, &fip2);
-		fip2.fx += fip1.fx;			fip2.fy += fip1.fy;
-		fip2.fz += fip1.fz;
-		}
-	//calc output-device coordinates of cubic brick: 8 corners
-	tmp.fx = -(width/2.0);			tmp.fz = (depth/2.0);	tmp.fy = 0.0;
-	o->uvec2ivec(&tmp, &itmp);
-	cpt[0].fx= fip1.fx+itmp.fx;	cpt[0].fy= fip1.fy+itmp.fy;	cpt[0].fz= fip1.fz+itmp.fz;
-	cpt[2].fx= fip1.fx-itmp.fx;	cpt[2].fy= fip1.fy-itmp.fy;	cpt[2].fz= fip1.fz-itmp.fz;
-	cpt[4].fx= fip2.fx+itmp.fx;	cpt[4].fy= fip2.fy+itmp.fy;	cpt[4].fz= fip2.fz+itmp.fz;
-	cpt[6].fx= fip2.fx-itmp.fx;	cpt[6].fy= fip2.fy-itmp.fy;	cpt[6].fz= fip2.fz-itmp.fz;
-	tmp.fx = (width/2.0);			tmp.fz = (depth/2.0);	tmp.fy = 0.0;
-	o->uvec2ivec(&tmp, &itmp);
-	cpt[1].fx= fip1.fx+itmp.fx;	cpt[1].fy= fip1.fy+itmp.fy;	cpt[1].fz= fip1.fz+itmp.fz;
-	cpt[3].fx= fip1.fx-itmp.fx;	cpt[3].fy= fip1.fy-itmp.fy;	cpt[3].fz= fip1.fz-itmp.fz;
-	cpt[5].fx= fip2.fx+itmp.fx;	cpt[5].fy= fip2.fy+itmp.fy;	cpt[5].fz= fip2.fz+itmp.fz;
-	cpt[7].fx= fip2.fx-itmp.fx;	cpt[7].fy= fip2.fy-itmp.fy;	cpt[7].fz= fip2.fz-itmp.fz;
-	//set up 6 faces
-	pg[0].fx = pg[4].fx = cpt[0].fx;	pg[1].fx = cpt[1].fx;	
-	pg[2].fx = cpt[2].fx;				pg[3].fx = cpt[3].fx;
-	pg[0].fy = pg[4].fy = cpt[0].fy;	pg[1].fy = cpt[1].fy;	
-	pg[2].fy = cpt[2].fy;				pg[3].fy = cpt[3].fy;
-	pg[0].fz = pg[4].fz = cpt[0].fz;	pg[1].fz = cpt[1].fz;	
-	pg[2].fz = cpt[2].fz;				pg[3].fz = cpt[3].fz;
-	faces[0] = new plane(this, data, pg, 5, &Line, &Fill);
-	pg[2].fx = cpt[5].fx;				pg[3].fx = cpt[4].fx;
-	pg[2].fy = cpt[5].fy;				pg[3].fy = cpt[4].fy;
-	pg[2].fz = cpt[5].fz;				pg[3].fz = cpt[4].fz;
-	npl = new plane(this, data, pg, 5, &Line, &Fill);
-	if(npl->GetSize(SIZE_MAX_Z) > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
-	else {
-		faces[1] = faces[0];		faces[0] = npl;		
-		}
-	pg[0].fx = pg[4].fx = cpt[2].fx;	pg[1].fx = cpt[6].fx;	
-	pg[2].fx = cpt[5].fx;				pg[3].fx = cpt[1].fx;
-	pg[0].fy = pg[4].fy = cpt[2].fy;	pg[1].fy = cpt[6].fy;	
-	pg[2].fy = cpt[5].fy;				pg[3].fy = cpt[1].fy;
-	pg[0].fz = pg[4].fz = cpt[2].fz;	pg[1].fz = cpt[6].fz;	
-	pg[2].fz = cpt[5].fz;				pg[3].fz = cpt[1].fz;
-	npl = new plane(this, data, pg, 5, &Line, &Fill);
-	if((dtmp = npl->GetSize(SIZE_MAX_Z)) > faces[1]->GetSize(SIZE_MAX_Z)) faces[2] = npl;
-	else {
-		faces[2] = faces[1];
-		if(dtmp > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
-		else {
-			faces[1] = faces[0];	faces[0] = npl;
-			}
-		}
-	pg[2].fx = cpt[7].fx;				pg[3].fx = cpt[3].fx;
-	pg[2].fy = cpt[7].fy;				pg[3].fy = cpt[3].fy;
-	pg[2].fz = cpt[7].fz;				pg[3].fz = cpt[3].fz;
-	npl = new plane(this, data, pg, 5, &Line, &Fill);
-	dtmp = npl->GetSize(SIZE_MAX_Z);
-	for (i = 3; i; i--) {
-		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
-			faces[i] = npl;			break;
-			}
-		else faces[i] = faces[i-1];
-		}
-	if(!i) faces[0] = npl;
-	pg[0].fx = pg[4].fx = cpt[4].fx;	pg[1].fx = cpt[7].fx;	
-	pg[2].fx = cpt[3].fx;				pg[3].fx = cpt[0].fx;
-	pg[0].fy = pg[4].fy = cpt[4].fy;	pg[1].fy = cpt[7].fy;	
-	pg[2].fy = cpt[3].fy;				pg[3].fy = cpt[0].fy;
-	pg[0].fz = pg[4].fz = cpt[4].fz;	pg[1].fz = cpt[7].fz;	
-	pg[2].fz = cpt[3].fz;				pg[3].fz = cpt[0].fz;
-	npl = new plane(this, data, pg, 5, &Line, &Fill);
-	dtmp = npl->GetSize(SIZE_MAX_Z);
-	for (i = 4; i; i--) {
-		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
-			faces[i] = npl;			break;
-			}
-		else faces[i] = faces[i-1];
-		}
-	if(!i) faces[0] = npl;
-	pg[2].fx = cpt[6].fx;				pg[3].fx = cpt[5].fx;
-	pg[2].fy = cpt[6].fy;				pg[3].fy = cpt[5].fy;
-	pg[2].fz = cpt[6].fz;				pg[3].fz = cpt[5].fz;
-	npl = new plane(this, data, pg, 5, &Line, &Fill);
-	dtmp = npl->GetSize(SIZE_MAX_Z);
-	for (i = 5; i; i--) {
-		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
-			faces[i] = npl;			break;
-			}
-		else faces[i] = faces[i-1];
-		}
-	if(!i) faces[0] = npl;
-	rDims.left = rDims.right = (int)pg[0].fx;
-	rDims.top = rDims.bottom = (int)pg[0].fy;
-	for (i= 3; i < 6; i++) if(faces[i]) {
-		faces[i]->DoPlot(o);
-		UpdateMinMaxRect(&rDims, faces[i]->rDims.left, faces[i]->rDims.top);
-		UpdateMinMaxRect(&rDims, faces[i]->rDims.right, faces[i]->rDims.bottom);
-		}
-	free(pg);
-}
-
-void
-Brick::DoMark(anyOutput *o, bool mark)
-{
-	int i;
-
-	if(mark){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
-		mo = GetRectBitmap(&mrc, o);
-		if(faces) for(i = 3; i < 6; i++)
-			if(faces[i]) faces[i]->DoMark(o, mark);
-		o->UpdateRect(&rDims, false);
-		}
-	else if(mo)	RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-Brick::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name) free(name);		name = 0L;
-		return true;
-	case CMD_LEGEND:
-		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Line, &Fill);
-		break;
-	case CMD_BAR_FILL:
-		if(tmpl) {
-			memcpy(&Fill, tmpl, sizeof(FillDEF));
-			Fill.hatch = 0L;
-			return true;
-			}
-		break;
-	case CMD_MRK_DIRTY:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_BRICK;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_REDRAW:
-		//Note: this command is issued either by Undo (no output given) or
-		//  by Plot3D::DoPlot after sorting all objects (output specified)
-		if(!parent) return false;
-		if(!o) return parent->Command(cmd, tmpl, o);
-		//Should we ever come here ?
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				if(faces && faces[3] && faces[4] && faces[5] &&
-					(faces[3]->ObjThere(mev->x, mev->y) || 
-					faces[4]->ObjThere(mev->x, mev->y) ||
-					faces[5]->ObjThere(mev->x, mev->y))){
-						o->ShowMark(CurrGO=this, MRK_GODRAW);
-						return true;
-						}
-				}
-			break;
-			}
-		break;
-	case CMD_UPDATE:
-		if(ssRef && cssRef > 5 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &depth);
-			data->GetValue(ssRef[4].y, ssRef[4].x, &width);
-			data->GetValue(ssRef[5].y, ssRef[5].x, &height);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
-			if(flags & 0x800L) {		//height is data
-				((Plot*)parent)->CheckBounds3D(fPos.fx, height, fPos.fz);
-				}
-			return true;
-			}
-		break;
-	case CMD_SET_GO3D:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// line_segment: utility object to draw a piece of a polyline in 3D space
-line_segment::line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2)
-	:GraphObj(par, d)
-{
-	double tmp, tmp1, tmp2;
-
-	nli = 0;    nldata = 0L;	  ldata = 0L;	prop = 1.0;		df_go = 0L;
-	fmin.fx = fmax.fx = fmin.fy = fmax.fy = fmin.fz = fmax.fz = 0.0;
-	ndf_go = 0;
-	if(ld) memcpy(&Line, ld, sizeof(LineDEF));
-	if(p1 && p2 &&(ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
-		(ldata[0] = (POINT3D*)malloc(2 * sizeof(POINT3D))) &&
-		(nldata = (int*)calloc(1, sizeof(int)))){
-			if(Line.pattern) {
-				tmp1 = (tmp = (p2->x - p1->x)) * tmp;
-				tmp2 = (tmp1 += (tmp = (p2->y - p1->y)) * tmp);
-				tmp1 += (tmp = (p2->z - p1->z)) * tmp;
-				if(tmp1 > 1.0) prop = sqrt(tmp2)/sqrt(tmp1);
-				}
-			memcpy(&ldata[0][0], p1, sizeof(POINT3D));
-			memcpy(&ldata[0][1], p2, sizeof(POINT3D));
-			nldata[0] = 2;		nli = 1;
-			rDims.left = rDims.right = p1->x;	rDims.top = rDims.bottom = p1->y;
-			UpdateMinMaxRect(&rDims, p2->x, p2->y);
-			fmin.fx = (double)rDims.left;	fmin.fy = (double)rDims.top;
-			fmax.fx = (double)rDims.right;	fmax.fy = (double)rDims.bottom;
-			if(p2->z > p1->z) {
-				fmin.fz = (double)p1->z;	fmax.fz = (double)p2->z;
-				}
-			else {
-				fmin.fz = (double)p2->z;	fmax.fz = (double)p1->z;
-				}
-		}
-	Id = GO_LINESEG;
-}
-
-line_segment::~line_segment()
-{
-	int i;
-
-	if(ldata) {
-		for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
-		free(ldata);
-		}
-	if(nldata) free(nldata);		nldata = 0L;
-}
-
-double
-line_segment::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_MIN_Z:
-		return fmin.fz;
-	case SIZE_MAX_Z:
-		return fmax.fz;
-		}
-	return 0.0;
-}
-
-void
-line_segment::DoPlot(anyOutput *o)
-{
-	bDrawDone = false;		co = 0L;
-	if(df_go) free(df_go);
-	df_go = 0L;				ndf_go = 0;
-	if(o->VPscale > 1.5 && (
-		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
-		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
-		bDrawDone = true;		return;
-		}
-	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
-	Command(CMD_REDRAW, 0L, o);
-}
-
-bool
-line_segment::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i, j;
-	POINT pts[2];
-	LineDEF cLine;
-	POINT3D *ap;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		if(parent) return parent->Command(cmd, tmpl, o);
 		break;
-	case CMD_DRAW_LATER:
-		if(!co) return false;
-		if(df_go){
-			for(i = 0; i < ndf_go; i++) if(df_go[i] == co) return true;
-			if(df_go = (GraphObj**)realloc(df_go, (ndf_go +1) * sizeof(GraphObj*))) {
-				df_go[ndf_go++] = co;
-				}
-			}
-		else {
-			if(df_go = (GraphObj**)malloc(sizeof(GraphObj*))){
-				df_go[0] = co;	ndf_go = 1;
-				}
-			}
-		return true;
-	case CMD_REDRAW:
-		if(bDrawDone) return false;
-		bDrawDone = true;
-		if(!nli) return false;
-		if(df_go) {
-			for(i = 0; i < ndf_go; i++) if(df_go[i]) df_go[i]->Command(cmd, tmpl, o);
-			free(df_go);	df_go = 0L;			ndf_go = 0L;
-			}
-		if(o && ldata && nldata){
-			memcpy(&cLine, &Line, sizeof(LineDEF));
-			cLine.patlength *= prop;
-			o->SetLine(&cLine);
-			for(i = 0; i < nli; i++) for(j = 0; j < (nldata[i]-1); j++) {
-				pts[0].x = ldata[i][j].x;	pts[0].y = ldata[i][j].y;
-				pts[1].x = ldata[i][j+1].x;	pts[1].y = ldata[i][j+1].y;
-				if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) o->oPolyline(pts, 2);
-				}
-			}
-		return true;
-	case CMD_CLIP:
-		if(co = (GraphObj*)tmpl){
-			switch(co->Id) {
-			case GO_PLANE:
-			case GO_SPHERE:
-				DoClip(co);
-				break;
-				}
-			}
-		return false;
-	case CMD_STARTLINE:
-		if(tmpl) {
-			if(ldata && nldata) {
-				ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
-				ldata[nli] = (POINT3D*)malloc(2 * sizeof(POINT3D));
-				nldata = (int*)realloc(nldata, sizeof(int)*(nli+1));
-				}
-			else {
-				ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
-				ldata[nli = 0] = (POINT3D*)malloc(2 * sizeof(POINT3D));
-				nldata = (int*)calloc(1, sizeof(int));
-				}
-			if(ldata && nldata) {
-				memcpy(&ldata[nli][0], tmpl, sizeof(POINT3D));
-				memcpy(&ldata[nli][1], tmpl, sizeof(POINT3D));
-				nldata[nli++] = 1;
-				return true;
-				}
-			}
-		break;
-	case CMD_ADDTOLINE:
-		if((ap = (POINT3D*)tmpl) && ldata && nldata && nli && nldata[i =(nli-1)]) {
-			j = nldata[i];
-			ldata[i] = (POINT3D*)realloc(ldata[i], (nldata[i]+2) * sizeof(POINT3D));
-			if(j && ldata[i][j-1].x == ap->x && ldata[i][j-1].y == ap->y &&
-				ldata[i][j-1].z == ap->z) return true;
-			else {
-				j = (nldata[i]++);
-				}
-			memcpy(&ldata[i][j-1], tmpl, sizeof(POINT3D));
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-void *
-line_segment::ObjThere(int x, int y)
-{
-	int i, j;
-	POINT pts[2];
-
-	if(ldata && nldata){
-		for(i = 0; i < nli; i++) for(j = 0; j < nldata[i]; j +=2) {
-			pts[0].x = ldata[i][j].x;	pts[0].y = ldata[i][j].y;
-			pts[1].x = ldata[i][j+1].x;	pts[1].y = ldata[i][j+1].y;
-			if(IsCloseToLine(&pts[0], &pts[1], x, y))return this;
-			}
-		}
-	return 0L;
-}
-
-void
-line_segment::DoClip(GraphObj *co)
-{
-	RECT cliprc;
-	int o_nli, *o_nldata = 0L;
-	POINT3D **o_ldata = 0L, *pts = 0L, *pla;
-	int i, j, k, np, r, cx, cy, cz;
-	bool is_valid = false;
-
-	cliprc.left = iround(co->GetSize(SIZE_MIN_X));
-	cliprc.right = iround(co->GetSize(SIZE_MAX_X));
-	cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
-	cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
-	if(OverlapRect(&rDims, &cliprc)) {
-		if(!(pts = (POINT3D*)calloc(2, sizeof(POINT3D))))return;
-		o_nli = nli;		nli = 0;
-		o_nldata = nldata;	nldata = 0L;
-		o_ldata = ldata;	ldata = 0L;
-		switch(co->Id) {
-		case GO_SPHERE:
-			cx = iround(co->GetSize(SIZE_XPOS));
-			cy = iround(co->GetSize(SIZE_YPOS));
-			cz = iround(co->GetSize(SIZE_ZPOS));
-			r = iround(co->GetSize(SIZE_RADIUS1));
-			for(i = 0; i < o_nli; i++) for(j = 0; j < (o_nldata[i]-1); j ++) {
-				pts[0].x = o_ldata[i][j].x;			pts[0].y = o_ldata[i][j].y;
-				pts[0].z = o_ldata[i][j].z;			pts[1].x = o_ldata[i][j+1].x;
-				pts[1].y = o_ldata[i][j+1].y;		pts[1].z = o_ldata[i][j+1].z;
-				clip_line_sphere(this, &pts, r, cx, cy, cz);
-				}
-			break;
-		case GO_PLANE:
-			for(i = 0; ((plane*)co)->GetPolygon(&pla, &np, i); i++){
-				for(j = 0; j < o_nli; j++) {
-					if(o_nldata[j] >1) for(k = 0; k < (o_nldata[j]-1); k++){
-						pts[0].x = o_ldata[j][k].x;			pts[0].y = o_ldata[j][k].y;
-						pts[0].z = o_ldata[j][k].z;			pts[1].x = o_ldata[j][k+1].x;
-						pts[1].y = o_ldata[j][k+1].y;		pts[1].z = o_ldata[j][k+1].z;
-						if(pts[0].x != pts[1].x || pts[0].y != pts[1].y || pts[0].z != pts[1].z)
-							clip_line_plane(this, &pts, pla, np, ((plane*)co)->GetVec());
-						}
-					}
-				if(nli) is_valid = true;
-				if(o_ldata) {
-					for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
-					free(o_ldata);
-					}
-				if(o_nldata) free(o_nldata);
-				o_nli = nli;		nli = 0;
-				o_nldata = nldata;	nldata = 0L;
-				o_ldata = ldata;	ldata = 0L;
-				if(!o_nli) return;				//line is completly hidden
-				}
-			if(is_valid || i==0){
-				nli = o_nli;		o_nli = 0;
-				nldata = o_nldata;	o_nldata = 0L;
-				ldata = o_ldata;	o_ldata = 0L;
-				}
-			break;
-		default:
-			nli = o_nli;		o_nli = 0;
-			nldata = o_nldata;	o_nldata = 0L;
-			ldata = o_ldata;	o_ldata = 0L;
-			break;
-			}
-		if(pts) free(pts);
-		}
-	if(o_ldata) {
-		for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
-		free(o_ldata);
-		}
-	if(o_nldata) free(o_nldata);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// define a drop line in 3D space
-DropLine3D::DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc,
-		int xr, int yc, int yr, int zc, int zr):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	Id = GO_DROPL3D;
-	memcpy(&fPos, p1, sizeof(fPOINT3D));
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = zc;	ssRef[2].y = zr;
-			cssRef = 3;
-			}
-		}
-	bModified = false;
-	type = 0x01;
-}
-
-DropLine3D::DropLine3D(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-DropLine3D::~DropLine3D()
-{
-	if(bModified) Undo.InvalidGO(this);
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-void
-DropLine3D::DoPlot(anyOutput *o)
-{
-	fPOINT3D fip, fp, fp1;
-	POINT3D p1, p2;
-	int i;
-
-	if(!parent || !o || !o->fvec2ivec(&fPos, &fip)) return;
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	for(i = 0; i < 6; i++){
-		if(ls[i]) delete(ls[i]);
-		ls[i] = 0L;
-		}
-	p1.x = iround(fip.fx);	p1.y = iround(fip.fy);	p1.z = iround(fip.fz);
-	rDims.left = rDims.right = p1.x;	rDims.top = rDims.bottom = p1.y;
-	for(i = 0; i < 6; i++) {
-		fp.fx = fPos.fx;	fp.fy = fPos.fy;	fp.fz = fPos.fz;
-		if(type & (1 << i)){
-			switch (i) {
-			case 0:	fp.fy = parent->GetSize(SIZE_BOUNDS_YMIN);	break;
-			case 1:	fp.fy = parent->GetSize(SIZE_BOUNDS_YMAX);	break;
-			case 2:	fp.fz = parent->GetSize(SIZE_BOUNDS_ZMIN);	break;
-			case 3:	fp.fz = parent->GetSize(SIZE_BOUNDS_ZMAX);	break;
-			case 4:	fp.fx = parent->GetSize(SIZE_BOUNDS_XMIN);	break;
-			case 5:	fp.fx = parent->GetSize(SIZE_BOUNDS_XMAX);	break;
-				}
-			o->fvec2ivec(&fp, &fp1);		p2.x = iround(fp1.fx);
-			p2.y = iround(fp1.fy);			p2.z = iround(fp1.fz);
-			UpdateMinMaxRect(&rDims, p2.x, p2.y);
-			if(ls[i] = new line_segment(this, data, &Line, &p1, &p2)) ls[i]->DoPlot(o);
-			mpts[i][0].x = p1.x;	mpts[i][0].y = p1.y;
-			mpts[i][1].x = p2.x;	mpts[i][1].y = p2.y;
-			}
-		}
-	IncrementMinMaxRect(&rDims, 5);
-}
-
-void
-DropLine3D::DoMark(anyOutput *o, bool mark)
-{
-	int i;
-
-	if(mark) {
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
-		mo = GetRectBitmap(&mrc, o);
-		for(i = 0; i < 6; i++) {
-			if(type & (1 << i)){
-				InvertLine(mpts[i], 2, &Line, 0L, o, mark);
-				}
-			}
-		o->UpdateRect(&mrc, false);
-		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-DropLine3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	int i;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		for(i = 0; i < 6; i++){
-			if(ls[i]) delete(ls[i]);
-			ls[i] = 0L;
-			}
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name) free(name);		name = 0L;
-		return true;
-	case CMD_DL_TYPE:
-		if(tmpl && *((int*)tmpl)) type = *((int*)tmpl);
-		return true;
-	case CMD_DL_LINE:
-		if(tmpl) memcpy(&Line, tmpl, sizeof(LineDEF));
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_DROPL3D;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_REDRAW:
-		//Note: this command is issued either by Undo (no output given) or
-		//  by Plot3D::DoPlot after sorting all objects (output specified)
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				for(i = 0; i < 6; i++) {
-					if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
-						o->ShowMark(this, MRK_GODRAW);
-						return true;
-						}
-					}
-				}
-			break;
-			}
-		break;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >2 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
-			return true;
-			}
-		break;
-	case CMD_SET_GO3D:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// define an arrow in 3D space
-Arrow3D::Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1,
-		int xr1, int yc1, int yr1, int zc1, int zr1, int xc2, int xr2, int yc2, 
-		int yr2, int zc2, int zr2):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	Id = GO_ARROW3D;
-	memcpy(&fPos1, p1, sizeof(fPOINT3D));	memcpy(&fPos2, p2, sizeof(fPOINT3D));
-	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || zc1 >= 0 || zr1 >= 0 || 
-		xc2 >= 0 || xr2 >= 0 || yc2 >= 0 || yr2 >= 0 || zc2 >= 0 || zr2 >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
-			ssRef[0].x = xc1;	ssRef[0].y = xr1;
-			ssRef[1].x = yc1;	ssRef[1].y = yr1;
-			ssRef[2].x = zc1;	ssRef[2].y = zr1;
-			ssRef[3].x = xc2;	ssRef[3].y = xr2;
-			ssRef[4].x = yc2;	ssRef[4].y = yr2;
-			ssRef[5].x = zc2;	ssRef[5].y = zr2;
-			cssRef = 6;
-			}
-		}
-	bModified = false;
-}
-
-Arrow3D::Arrow3D(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-Arrow3D::~Arrow3D()
-{
-	if(bModified) Undo.InvalidGO(this);
-	Command(CMD_FLUSH, 0L, 0L);
-}
-
-bool
-Arrow3D::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_ARROW_LINE:
-		Line.width = value;
-		return true;
-	case SIZE_ARROW_CAPWIDTH:
-		cw = value;
-		return true;
-	case SIZE_ARROW_CAPLENGTH:
-		cl = value;
-		return true;
-		}
-	return false;
-}
-
-bool
-Arrow3D::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_ARROW:
-		Line.color = col;
-		return true;
-		}
-	return false;
-}
-
-void
-Arrow3D::DoPlot(anyOutput *o)
-{
-	double si, csi, tmp, cwr, clr, d, d1, d2;
-	fPOINT3D fip1, fip2, tria[3];
-	POINT3D p1, p2, cp1, cp2;
-	FillDEF fill;
-	int i;
-
-	if(!parent || !o || !o->fvec2ivec(&fPos1, &fip1) ||!o->fvec2ivec(&fPos2, &fip2)) return;
-	for(i = 0; i < 3; i++){
-		if(ls[i]) delete(ls[i]);
-		ls[i] = 0L;
-		}
-	p1.x = iround(fip1.fx);	p1.y = iround(fip1.fy);	p1.z = iround(fip1.fz);
-	p2.x = iround(fip2.fx);	p2.y = iround(fip2.fy);	p2.z = iround(fip2.fz);
-	if(p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) return;	//zero length arrow
-	rDims.left = rDims.right = p1.x;	rDims.top = rDims.bottom = p1.y;
-	UpdateMinMaxRect(&rDims, p2.x, p2.y);
-	IncrementMinMaxRect(&rDims, 5);
-	if(ls[0] = new line_segment(this, data, &Line, &p1, &p2)) ls[0]->DoPlot(o);
-	mpts[0][0].x = p1.x;	mpts[0][0].y = p1.y;	mpts[0][1].x = p2.x;	mpts[0][1].y = p2.y;
-	if(p1.x == p2.x && p1.y == p2.y) return;			//zero length in 2D
-	if((type & 0xff) == ARROW_NOCAP) return;			//no cap;
-	//calculate sine and cosine for cap
-	si = fip1.fy-fip2.fy;
-	tmp = fip2.fx - fip1.fx;
-	si = si/sqrt(si*si + tmp*tmp);
-	csi = fip2.fx-fip1.fx;
-	tmp = fip2.fy - fip1.fy;
-	csi = csi/sqrt(csi*csi + tmp*tmp);
-	//cap corners
-	d1 = (d = fip2.fx - fip1.fx) * d;
-	d1 += ((d = fip2.fy - fip1.fy) * d);
-	d2 = d1 + ((d = fip2.fz - fip1.fz) * d);
-	d1 = sqrt(d1);	d2 = sqrt(d2);	d = d1/d2;
-	cwr = cw;	clr = cl*d;
-	cp1.x = p2.x - o->un2ix(csi*clr + si*cwr/2.0);
-	cp1.y = p2.y + o->un2iy(si*clr - csi*cwr/2.0);
-	cp2.x = p2.x - o->un2ix(csi*clr - si*cwr/2.0);
-	cp2.y = p2.y + o->un2iy(si*clr + csi*cwr/2.0);
-	cp1.z = cp2.z = p2.z;
-	mpts[1][0].x = p2.x;	mpts[1][0].y = p2.y;	mpts[1][1].x = cp1.x;	mpts[1][1].y = cp1.y;
-	mpts[2][0].x = p2.x;	mpts[2][0].y = p2.y;	mpts[2][1].x = cp2.x;	mpts[2][1].y = cp2.y;
-	if((type & 0xff) == ARROW_LINE) {
-		if(ls[1] = new line_segment(this, data, &Line, &p2, &cp1)) ls[1]->DoPlot(o);
-		if(ls[2] = new line_segment(this, data, &Line, &p2, &cp2)) ls[2]->DoPlot(o);
-		}
-	else if((type & 0xff) == ARROW_TRIANGLE) {
-		fill.type = FILL_NONE;	fill.color = Line.color;
-		fill.scale = 1.0;		fill.hatch = 0L;
-		tria[0].fz = tria[1].fz = tria[2].fz = fip2.fz;
-		tria[0].fx = cp1.x;		tria[0].fy = cp1.y;
-		tria[1].fx = fip2.fx;	tria[1].fy = fip2.fy;
-		tria[2].fx = cp2.x;		tria[2].fy = cp2.y;
-		if(cap = new plane(this, data, tria, 3, &Line, &fill))cap->DoPlot(o);
-	}
-}
-
-void
-Arrow3D::DoMark(anyOutput *o, bool mark)
-{
-	int i;
-
-	if(mark) {
-		for(i = 0; i < 3; i++) {
-			if(ls[i]){
-				InvertLine(mpts[i], 2, &Line, 0L, o, mark);
-				}
-			}
-		}
-	else if(parent) parent->Command(CMD_REDRAW, 0L, o);
-}
-
-bool
-Arrow3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	int i;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		for(i = 0; i < 3; i++){
-			if(ls[i]) delete(ls[i]);
-			ls[i] = 0L;
-			}
-		if(cap) delete(cap);	cap = 0L;
-		if(ssRef) free(ssRef);		ssRef = 0L;
-		if(name) free(name);		name = 0L;
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_ARROW3D;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_MRK_DIRTY:			//from Undo ?
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
-				for(i = 0; i < 3; i++) {
-					if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
-						o->ShowMark(this, MRK_GODRAW);
-						return true;
-						}
-					}
-				}
-			break;
-			}
-		break;
-	case CMD_ARROW_ORG3D:
-		if(tmpl) memcpy(&fPos1, tmpl, sizeof(fPOINT3D));
-		return true;
-	case CMD_ARROW_TYPE:
-		if(tmpl) type = *((int*)tmpl);
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >5 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos2.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos2.fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos2.fz);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &fPos1.fx);
-			data->GetValue(ssRef[4].y, ssRef[4].x, &fPos1.fy);
-			data->GetValue(ssRef[5].y, ssRef[5].x, &fPos1.fz);
-			return true;
-			}
-		return false;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
-			((Plot*)parent)->CheckBounds3D(fPos1.fx, fPos1.fy, fPos1.fz);
-			((Plot*)parent)->CheckBounds3D(fPos2.fx, fPos2.fy, fPos2.fz);
-			return true;
-			}
-		break;
-	case CMD_SET_GO3D:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// a data line in 3D space
-Line3D::Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz)
-	:GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	if(rx && rx[0]) x_range = strdup(rx);	if(ry && ry[0]) y_range = strdup(ry);
-	if(rz && rz[0]) z_range = strdup(rz);
-	DoUpdate();
-	Id = GO_LINE3D;
-	bModified = false;
-}
-
-Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, int xc1, int xr1, int yc1, int yr1,
-		int zc1, int zr1, int xc2, int xr2, int yc2, int yr2, int zc2, int zr2)
-	:GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	if(pt && n_pt) {
-		values = (fPOINT3D*)memdup(pt, n_pt * sizeof(fPOINT3D), 0L);
-		nPts = n_pt;
-		ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
-		}
-	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || zc1 >= 0 || zr1 >= 0 || 
-		xc2 >= 0 || xr2 >= 0 || yc2 >= 0 || yr2 >= 0 || zc2 >= 0 || zr2 >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
-			ssRef[0].x = xc1;	ssRef[0].y = xr1;
-			ssRef[1].x = yc1;	ssRef[1].y = yr1;
-			ssRef[2].x = zc1;	ssRef[2].y = zr1;
-			ssRef[3].x = xc2;	ssRef[3].y = xr2;
-			ssRef[4].x = yc2;	ssRef[4].y = yr2;
-			ssRef[5].x = zc2;	ssRef[5].y = zr2;
-			cssRef = 6;
+	case CMD_SET_DATAOBJ:
+		Id = GO_BUBBLE;
+		data = (DataObj*)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >2 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &fs);
+			return true;
 			}
-		}
-	Id = GO_LINE3D;
-	bModified = false;
-}
-
-Line3D::Line3D(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-Line3D::~Line3D()
-{
-	int i;
-
-	if(bModified) Undo.InvalidGO(this);
-	if(ls){
-		for(i = 0; i < (nPts-1); i++) if(ls[i]) delete(ls[i]);
-		free(ls);
-		}
-	if(pts && npts) free(pts);		pts = 0L;		npts = 0;	cssRef = 0;
-	if(x_range) free(x_range);		x_range = 0L;
-	if(y_range) free(y_range);		y_range = 0L;
-	if(z_range) free(z_range);		z_range = 0L;
-	if(values) free(values);		values = 0L;
-	if(ssRef) free(ssRef);			ssRef = 0L;
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-}
-
-void
-Line3D::DoPlot(anyOutput *o)
-{
-	int i, j;
-	fPOINT3D fip;
-	POINT3D p1, p2;
-	POINT np;
-
-
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-	if(ls) {
-		if(pts && npts) free(pts);
-		npts = 0;	if(!(pts = (POINT*)calloc(nPts, sizeof(POINT))))return;
-		for(i = 0; i< nPts; i++) {
-			if(!o->fvec2ivec(&values[i], &fip)) return;
-			p2.x = iround(fip.fx);	p2.y = iround(fip.fy);	p2.z = iround(fip.fz);
-			np.x = p2.x;			np.y = p2.y;
-			AddToPolygon(&npts, pts, &np);
-			if(i) {
-				UpdateMinMaxRect(&rDims, np.x, np.y);
-				j = i-1;
-				if(ls[j]) delete(ls[j]);
-				if(ls[j] = new line_segment(this, data, &Line, &p1, &p2)) {
-					ls[j]->DoPlot(o);
-					}
-				}
-			else {
-				rDims.left = rDims.right = p2.x;
-				rDims.top = rDims.bottom = p2.y;
-				}
-			p1.x = p2.x;	p1.y = p2.y;	p1.z = p2.z;
-			}
-		IncrementMinMaxRect(&rDims, 6);
-		}
-}
-
-void
-Line3D::DoMark(anyOutput *o, bool mark)
-{
-	if(mark) {
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
-		mo = GetRectBitmap(&mrc, o);
-		InvertLine(pts, npts, &Line, &rDims, o, true);
-		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-Line3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	POINT p1;
-	int i;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(name) free(name);		name = 0L;
-		return true;
-	case CMD_SET_LINE:
+		return false;
+	case CMD_BUBBLE_ATTRIB:
 		if(tmpl) {
-			memcpy(&Line, tmpl, sizeof(LineDEF));
+			type &= ~0xff0;
+			type |= (*((int*)tmpl) & 0xff0);
 			return true;
 			}
 		return false;
-	case CMD_SET_DATAOBJ:
-		Id = GO_LINE3D;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_REDRAW:
-		//Note: this command is issued  by Undo (no output given)
-		if(!parent) return false;
-		if(!o) return parent->Command(cmd, tmpl, o);
-		//Should we ever come here ?
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!IsInRect(&rDims, p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPts <2 ||
-				!IsCloseToPL(p1, pts, npts))return false;
-			o->ShowMark(CurrGO=this, MRK_GODRAW);
-			return true;
-			}
-		return false;
-	case CMD_UPDATE:
-		if(parent && parent->Id != GO_GRID3D) {
-			Undo.DataMem(this, (void**)&values, nPts * sizeof(fPOINT3D), &nPts, UNDO_CONTINUE);
-			}
-		if(ssRef && cssRef >5 && data && nPts == 2) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &values[0].fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &values[0].fy);
-			data->GetValue(ssRef[2].y, ssRef[2].x, &values[0].fz);
-			data->GetValue(ssRef[3].y, ssRef[3].x, &values[1].fx);
-			data->GetValue(ssRef[4].y, ssRef[4].x, &values[1].fy);
-			data->GetValue(ssRef[5].y, ssRef[5].x, &values[1].fz);
+	case CMD_BUBBLE_TYPE:
+		if(tmpl) {
+			type &= ~0x00f;
+			type |= (*((int*)tmpl) & 0x00f);
 			return true;
 			}
-		else DoUpdate();
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH){
-			if(min.fx == max.fx || min.fy == max.fy){	//z's may be equal !
-				min.fx = min.fy = min.fz = HUGE_VAL;
-				max.fx = max.fy = max.fz = -HUGE_VAL;
-				for(i = 0; i < nPts; i++) {
-					if(values[i].fx < min.fx) min.fx = values[i].fx;
-					if(values[i].fy < min.fy) min.fy = values[i].fy;
-					if(values[i].fz < min.fz) min.fz = values[i].fz;
-					if(values[i].fx > max.fx) max.fx = values[i].fx;
-					if(values[i].fy > max.fy) max.fy = values[i].fy;
-					if(values[i].fz > max.fz) max.fz = values[i].fz;
-					}
-				}
-			((Plot*)parent)->CheckBounds3D(min.fx, min.fy, min.fz);
-			((Plot*)parent)->CheckBounds3D(max.fx, max.fy, max.fz);
-			return true;
-			}
-		return false;
-	case CMD_SET_GO3D:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-		}
-	return false;
-}
-
-void
-Line3D::DoUpdate()
-{
-	int n1 = 0, ic = 0, i, j, k, l, m, n;
-	double x, y, z;
-	AccRange *rX=0L, *rY=0L, *rZ=0L;
-
-	if(!x_range || !y_range || !z_range) return;
-	if(values) free(values);	values = 0L;
-	if(ls) free(ls);			ls = 0L;
-	rX = new AccRange(x_range);
-	rY = new AccRange(y_range);
-	rZ = new AccRange(z_range);
-	min.fx = min.fy = min.fz = HUGE_VAL;	max.fx = max.fy = max.fz = -HUGE_VAL;
-	if(rX) n1 = rX->CountItems();
-	if(n1 && rY && rZ && (values = (fPOINT3D*)malloc(n1 * sizeof(fPOINT3D)))){
-		rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
-		rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
-		rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
-		do {
-			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && 
-				data->GetValue(n, m, &z)){
-				values[ic].fx = x;	values[ic].fy = y;	values[ic].fz = z;
-				if(x < min.fx) min.fx = x;	if(x > max.fx) max.fx = x;
-				if(y < min.fy) min.fy = y;	if(y > max.fy) max.fy = y;
-				if(z < min.fz) min.fz = z;	if(z > max.fz) max.fz = z;
-				ic++;
-				}
-			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
-		nPts = ic;
-		if(ic > 1) ls = (line_segment **)calloc(ic-1, sizeof(line_segment*));
-		}
-	if(rX) delete(rX);	if(rY) delete(rY); if(rZ) delete(rZ);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// the text label class 
-Label::Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
-	 int xc, int xr, int yc, int yr, int tc, int tr):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	fPos.fx = x;		fPos.fy = y;		flags = flg;
-	if(parent){
-		fDist.fx = parent->GetSize(SIZE_LB_XDIST);
-		fDist.fy = parent->GetSize(SIZE_LB_YDIST);
-		}
-	Id = GO_LABEL;
-	if(td){
-		memcpy(&TextDef, td, sizeof(TextDEF));
-		if(td->text) TextDef.text = strdup(td->text);
-		}
-	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || tc >= 0 || tr >= 0) {
-		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
-			ssRef[0].x = xc;	ssRef[0].y = xr;
-			ssRef[1].x = yc;	ssRef[1].y = yr;
-			ssRef[2].x = tc;	ssRef[2].y = tr;
-			cssRef = 3;
-			}
-		}
-}
-
-Label::Label(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-Label::~Label()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-	if(fmt_txt) delete(fmt_txt);			fmt_txt = 0L;
-	if(bModified)Undo.InvalidGO(this);
-}
-
-double
-Label::GetSize(int select)
-{
-	switch(select){
-	case SIZE_CURSORPOS:
-		return (double)CursorPos;
-	case SIZE_CURSOR_XMIN:
-		return (double) (Cursor.right > Cursor.left ? Cursor.left : Cursor.right);
-	case SIZE_CURSOR_XMAX:
-		return (double) (Cursor.right > Cursor.left ? Cursor.right : Cursor.left);
-	case SIZE_CURSOR_YMIN:
-		return (double) (Cursor.bottom > Cursor.top ? Cursor.top : Cursor.bottom);
-	case SIZE_CURSOR_YMAX:
-		return (double) (Cursor.bottom > Cursor.top ? Cursor.bottom : Cursor.top);
-	case SIZE_MIN_Z:	case SIZE_MAX_Z:	case SIZE_ZPOS:
-		return curr_z;
-		}
-	return 0.0;
-}
-
-bool
-Label::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_LB_XDIST:			fDist.fx = value;		return true;
-	case SIZE_LB_YDIST:			fDist.fy = value;		return true;
-	case SIZE_XPOS:				fPos.fx = value;		return true;
-	case SIZE_YPOS:				fPos.fy = value;		return true;
-	case SIZE_ZPOS:				curr_z = value;			return is3D = true;
-		}
-	return false;
-}
-
-bool
-Label::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff) {
-	case COL_TEXT:
-		if(select & UNDO_STORESET) {
-			Undo.ValDword(this, &TextDef.ColTxt, UNDO_CONTINUE);
-			bModified = true;
-			}
-		TextDef.ColTxt = col;			bBGvalid = false;
+		return false;
+	case CMD_BUBBLE_FILL:
+		if(tmpl) {
+			BubbleFill.type = ((FillDEF*)tmpl)->type;
+			BubbleFill.color = ((FillDEF*)tmpl)->color;
+			BubbleFill.scale = ((FillDEF*)tmpl)->scale;
+			if(((FillDEF*)tmpl)->hatch)
+				memcpy(&BubbleFillLine, ((FillDEF*)tmpl)->hatch, sizeof(LineDEF));
+			}
 		return true;
-	case COL_BG:
-		bgcolor = col;	bBGvalid = true;
-		return true;
-		}
-	return false;
+	case CMD_BUBBLE_LINE:
+		if(tmpl) memcpy(&BubbleLine, tmpl, sizeof(LineDEF));
+		return true;
+	case CMD_AUTOSCALE:
+		return DoAutoscale(o);
+		break;
+		}
+	return false;
 }
-
-void
-Label::DoPlot(anyOutput *o)
+
+bool
+Bubble::DoAutoscale(anyOutput *o) 
 {
-	if(is3D && parent && parent->Command(CMD_SET_GO3D, this, o)) return;
-	DoPlotText(o);
+	double dx, dy;
+
+	switch(type & 0x0f0) {
+	case BUBBLE_XAXIS:			case BUBBLE_YAXIS:
+		dx = dy = fs/2.0;		break;
+	case BUBBLE_UNITS:
+		dx = fPos.fx/20;		dy = fPos.fy/20;		break;
+		}
+	((Plot*)parent)->CheckBounds(fPos.fx+dx, fPos.fy-dy);
+	((Plot*)parent)->CheckBounds(fPos.fx-dx, fPos.fy+dy);
+	return true;
 }
 
-void
-Label::DoMark(anyOutput *o, bool mark)
-{
-	DWORD bgpix[16];
-	int i, d, d1, ix, iy, dx, dy, n;
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bars are graphic objects
+Bar::Bar(GraphObj *par, DataObj *d, double x, double y, int which,int xc, int xr,
+		int yc, int yr, char *desc):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	fPos.fx = x;			fPos.fy = y;			type = which;
+	if(type & BAR_RELWIDTH) size = 60.0;			Id = GO_BAR;
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			cssRef = 2;
+			}
+		}
+	if(desc && desc[0]) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
+}
+
+Bar::Bar(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+Bar::~Bar()
+{
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Bar::GetSize(int select)
+{
+	switch(select){
+	case SIZE_XPOS:				return fPos.fx;
+	case SIZE_YPOS:				return fPos.fy;
+		}
+	return 0.0;
+}
+
+bool
+Bar::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_BAR: 
+		size = value;
+		return true;
+	case SIZE_BAR_LINE:
+		BarLine.width = value;
+		return true;
+	case SIZE_XBASE:
+		BarBase.fx = value;
+		return true;
+	case SIZE_YBASE:
+		BarBase.fy = value;
+		return true;
+		}
+	return false;
+}
+
+bool
+Bar::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_BAR_LINE:
+		BarLine.color = col;
+		return true;
+	case COL_BAR_FILL:
+		BarFill.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+Bar::DoPlot(anyOutput *target)
+{
+	int w;
+	double fBase, rsize;
+	POINT pts[2];
+
+	if(!parent || size <= 0.001) return;
+	target->SetLine(&BarLine);				target->SetFill(&BarFill);
+	switch(type & 0xff) {
+	case BAR_VERTU:		case BAR_VERTT:		case BAR_VERTB:
+		switch(type & 0xff) {
+		case BAR_VERTB:
+			fBase = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+			break;
+		case BAR_VERTT:
+			fBase = parent->GetSize(SIZE_BOUNDS_TOP);
+			break;
+		case BAR_VERTU:
+			fBase = BarBase.fy;
+			break;
+			}
+		if(type & BAR_RELWIDTH) {
+			rsize = size * parent->GetSize(SIZE_BARMINX)/100.0;
+			pts[0].x = iround(target->fx2fix(fPos.fx - rsize/2.0));
+			pts[1].x = iround(target->fx2fix(fPos.fx + rsize/2.0));
+			}
+		else {
+			w = target->un2ix(size);
+			pts[0].x = iround(target->fx2fix(fPos.fx)) - (w>>1);
+			pts[1].x = pts[0].x + w;
+			}
+		if(type & BAR_CENTERED) {
+			pts[0].y = iround(target->fy2fiy(fBase - (fPos.fy - fBase)));
+			pts[1].y = iround(target->fy2fiy(fBase + (fPos.fy - fBase)));
+			}
+		else {
+			pts[0].y = iround(target->fy2fiy(fBase));
+			pts[1].y = iround(target->fy2fiy(fPos.fy));
+			}
+		break;
+	case BAR_HORU:		case BAR_HORR:		case BAR_HORL:
+		switch(type & 0xff) {
+		case BAR_HORL:
+			fBase = parent->GetSize(SIZE_BOUNDS_LEFT);
+			break;
+		case BAR_HORR:
+			fBase = parent->GetSize(SIZE_BOUNDS_RIGHT);
+			break;
+		case BAR_HORU:
+			fBase = BarBase.fx;
+			break;
+			}
+		if(type & BAR_RELWIDTH) {
+			rsize = size * parent->GetSize(SIZE_BARMINY)/100.0;
+			pts[0].y = iround(target->fy2fiy(fPos.fy - rsize/2.0));
+			pts[1].y = iround(target->fy2fiy(fPos.fy + rsize/2.0));
+			}
+		else {
+			w = target->un2iy(size);
+			pts[0].y = target->fy2iy(fPos.fy) - w/2;
+			pts[1].y = pts[0].y+w;
+			}
+		if(type & BAR_CENTERED) {
+			pts[0].x = target->fx2ix(fBase - (fPos.fx - fBase));
+			pts[1].x = target->fx2ix(fBase + (fPos.fx - fBase));
+			}
+		else {
+			pts[0].x = target->fx2ix(fBase);
+			pts[1].x = target->fx2ix(fPos.fx);
+			}
+		break;
+	default:
+		return;
+		}
+	if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
+		target->oSolidLine(pts);
+		}
+	else target->oRectangle(pts[0].x, pts[0].y, pts[1].x, pts[1].y, name);
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+}
+
+void
+Bar::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		i = 2*o->un2ix(BarLine.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);
+		mo = GetRectBitmap(&mrc, o);
+		o->CopyBitmap(mrc.left, mrc.top, mo, 0, 0, mrc.right-mrc.left, mrc.bottom - mrc.top, true);
+		o->UpdateRect(&mrc, false);
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool 
+Bar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	FillDEF *TmpFill;
+	lfPOINT bl;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name)free(name);			name = 0L;
+		return true;
+	case CMD_SCALE:
+		if(!tmpl) return false;
+		if(!(type & BAR_RELWIDTH)) size *= ((scaleINFO*)tmpl)->sy.fy;
+		BarLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		BarLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		BarFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		((Legend*)tmpl)->HasFill(&BarLine, &BarFill, name);
+		break;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				o->ShowMark(CurrGO = this, MRK_GODRAW);
+				return true;
+				}
+			break;
+			}
+		return false;
+	case CMD_BAR_FILL:
+		TmpFill = (FillDEF *)tmpl;
+		if(TmpFill) {
+			BarFill.type = TmpFill->type;
+			BarFill.color = TmpFill->color;
+			BarFill.scale = TmpFill->scale;
+			if(TmpFill->hatch) memcpy(&HatchLine, TmpFill->hatch, sizeof(LineDEF));
+			}
+		return true;
+	case CMD_BAR_TYPE:
+		if(tmpl) type = *((int*)tmpl);
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_BAR;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >1 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+			switch(type & 0xff) {
+			case BAR_VERTU:
+			case BAR_VERTT:
+			case BAR_VERTB:
+				bl.fx = fPos.fx;
+				switch (type & 0xff) {
+				case BAR_VERTU:
+					bl.fy = BarBase.fy;
+					break;
+				case BAR_VERTT:
+				case BAR_VERTB:
+					bl.fy = 0.0f;		//cannot resolve
+					break;
+					}
+				if(type & BAR_CENTERED) bl.fy -= fPos.fy;
+				break;
+			case BAR_HORU:
+			case BAR_HORR:
+			case BAR_HORL:
+				bl.fy = fPos.fy;
+				switch(type & 0xff) {
+				case BAR_HORU:
+					bl.fx = BarBase.fx;
+				case BAR_HORR:
+				case BAR_HORL:
+					bl.fx = 0.0f;		//cannot resolve
+					}
+				if(type & BAR_CENTERED) bl.fx -= fPos.fx;
+				break;
+				}
+			((Plot*)parent)->CheckBounds(bl.fx, bl.fy);
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data line is a graphic object
+DataLine::DataLine(GraphObj *par, DataObj *d, char *xrange, char *yrange, char *nam):GraphObj(par, d)
+{
+	size_t cb;
+
+	FileIO(INIT_VARS);
+	Id = GO_DATALINE;
+	if(xrange && xrange[0]) {
+		cb = strlen(xrange) +2;		ssXref = (char*)malloc(cb);		rlp_strcpy(ssXref, (int)cb, xrange);
+		}
+	if(yrange && yrange[0]) {
+		cb = strlen(yrange) +2;		ssYref = (char*)malloc(cb);		rlp_strcpy(ssYref, (int)cb, yrange);
+		}
+	if(nam && nam[0]) name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
+	SetValues();
+}
+	
+DataLine::DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *na):GraphObj(par, d)
+{
+	int cb;
+
+	FileIO(INIT_VARS);
+	Values = val;			nPnt = nval;	nPntSet = nPnt-1;
+	if(na && na[0] && (name = (char*)malloc((cb = (int)strlen(na))+2))) {
+		rlp_strcpy(name, cb+1, na);
+		}
+	Id = GO_DATALINE;
+}
+
+DataLine::DataLine(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+DataLine::~DataLine()
+{
+	if(Values)free(Values);		Values = 0L;
+	if(pts) free(pts);			pts = 0L;
+	if(ssXref) free(ssXref);	ssXref = 0L;
+	if(ssYref) free(ssYref);	ssYref = 0L;
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(name) free(name);		name = 0L;
+	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+bool
+DataLine::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_DATA_LINE:
+		LineDef.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+DataLine::DoPlot(anyOutput *target)
+{
+	int i;
+	lfPOINT fip;
+	POINT pn, *tmppts;
+
+	if(!Values || nPntSet < 1) return;
+	if (nPntSet >= nPnt) nPntSet = nPnt-1;
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	if(pts) free(pts);				pts = 0L;
+	if((type & 0xff) == 9 || (type & 0xff) == 10) //splines
+		pts = (POINT *)malloc(sizeof(POINT)*1000);
+	else if(type & 0xff) pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2)*2);
+	else pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2));
+	if(!pts) return;
+	if(max.fx > min.fx && max.fy > min.fy) dirty = false;
+	else if(dirty) Command(CMD_AUTOSCALE, 0L, target);
+	cp = 0;
+	switch(type & 0x0f) {
+	case 0:		default:
+		for (i = 0; i <= nPntSet; i++){
+			target->fp2fip(Values+i, &fip);
+			pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+			AddToPolygon(&cp, pts, &pn);
+			}
+		break;
+	case 5:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		target->fp2fip(Values+1, &fip);
+		pn.y += (pn.y -iround(fip.fy))>>1;
+		AddToPolygon(&cp, pts, &pn);
+	case 1:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(+fip.fy);
+		for (i = 0; i <= nPntSet; i++){
+			target->fp2fip(Values+i, &fip);
+			pn.x = iround(fip.fx);			AddToPolygon(&cp, pts, &pn);
+			pn.y = iround(fip.fy);			AddToPolygon(&cp, pts, &pn);
+			}
+		if((type &0xf) == 5) {
+			target->fp2fip(Values+i-2, &fip);
+			pn.x += (pn.x - iround(fip.fx))>>1;
+			AddToPolygon(&cp, pts, &pn);
+			}
+		break;
+	case 6:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		target->fp2fip(Values+1, &fip);
+		pn.x += (pn.x - iround(fip.fx))>>1;
+		AddToPolygon(&cp, pts, &pn);
+	case 2:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		for (i = 0; i <= nPntSet; i++){
+			target->fp2fip(Values+i, &fip);
+			pn.y = iround(fip.fy);			AddToPolygon(&cp, pts, &pn);
+			pn.x = iround(fip.fx);			AddToPolygon(&cp, pts, &pn);
+			}
+		if((type &0xf) == 6) {
+			target->fp2fip(Values+i-2, &fip);
+			pn.y += (pn.y - iround(fip.fy))>>1;
+			AddToPolygon(&cp, pts, &pn);
+			}
+		break;
+	case 7:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		target->fp2fip(Values+1, &fip);
+		pn.x += (pn.x - iround(fip.fx))>>1;
+		AddToPolygon(&cp, pts, &pn);
+	case 3:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		for (i = 0; i <= nPntSet; i++){
+			target->fp2fip(Values+i, &fip);
+			pn.x = (pn.x + iround(fip.fx))>>1;	AddToPolygon(&cp, pts, &pn);
+			pn.y = iround(fip.fy);				AddToPolygon(&cp, pts, &pn);
+			pn.x = iround(fip.fx);
+			}
+		AddToPolygon(&cp, pts, &pn);
+		if((type &0xf) == 7) {
+			target->fp2fip(Values+i-2, &fip);
+			pn.x += (pn.x - iround(fip.fx))>>1;
+			AddToPolygon(&cp, pts, &pn);
+			}
+		break;
+	case 8:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		target->fp2fip(Values+1, &fip);
+		pn.y += (pn.y - iround(fip.fy))>>1;
+		AddToPolygon(&cp, pts, &pn);
+	case 4:
+		target->fp2fip(Values, &fip);
+		pn.x = iround(fip.fx);		pn.y = iround(fip.fy);
+		for (i = 0; i <= nPntSet; i++){
+			target->fp2fip(Values+i, &fip);
+			pn.y = (pn.y + iround(fip.fy))>>1;	AddToPolygon(&cp, pts, &pn);
+			pn.x = iround(fip.fx);				AddToPolygon(&cp, pts, &pn);
+			pn.y = iround(fip.fy);
+			}
+		AddToPolygon(&cp, pts, &pn);
+		if((type &0xf) == 8) {
+			target->fp2fip(Values+i-2, &fip);
+			pn.y += (pn.y - iround(fip.fy))>>1;
+			AddToPolygon(&cp, pts, &pn);
+			}
+		break;
+	case 9:		case 10:
+		DrawSpline(target);
+		break;
+		}
+	if(cp < 2) return;
+	if(isPolygon) {			//for mark polygon only !!
+		AddToPolygon(&cp, pts, pts);
+		}
+	else{
+		target->SetLine(&LineDef);		target->oPolyline(pts, cp);
+		}
+	if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+	i = 2*target->un2ix(LineDef.width);		//increase size of rectangle for marks
+	IncrementMinMaxRect(&rDims, i);
+}
+
+void
+DataLine::DoMark(anyOutput *o, bool mark)
+{
+	if(pts && cp && o){
+		if(mark){
+			memcpy(&mrc, &rDims, sizeof(RECT));
+			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+			mo = GetRectBitmap(&mrc, o);
+			InvertLine(pts, cp, &LineDef, &mrc, o, mark);
+			}
+		else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+		}
+}
+
+bool
+DataLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	bool bFound = false;
+	POINT p1;
+	int i;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPntSet <1)
+				return false; 
+			if(isPolygon && IsInPolygon(&p1, pts, cp)) bFound = true;
+			if(bFound || IsCloseToPL(p1,pts,cp)) 
+				return o->ShowMark(this, MRK_GODRAW);
+			}
+		break;
+	case CMD_SCALE:
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE;
+		data = (DataObj*)tmpl;
+		return true;
+	case CMD_MRK_DIRTY:
+		dirty= true;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, 0L);
+		return false;
+	case CMD_LEGEND:
+		if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+			if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L, name);
+			}
+		break;
+	case CMD_SET_LINE:
+		if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+		return true;
+	case CMD_UPDATE:
+		Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
+		Undo.ValLong(this, &nPntSet, UNDO_CONTINUE);
+		SetValues();
+		return true;
+	case CMD_AUTOSCALE:
+		if(nPntSet < 1 || !Values) return false;
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			if(dirty) {
+				min.fx = max.fx = Values[0].fx;	min.fy = max.fy = Values[0].fy;
+				for (i = 1; i <= nPntSet; i++){
+					min.fx = Values[i].fx < min.fx ? Values[i].fx : min.fx;
+					max.fx = Values[i].fx > max.fx ? Values[i].fx : max.fx;
+					min.fy = Values[i].fy < min.fy ? Values[i].fy : min.fy;
+					max.fy = Values[i].fy > max.fy ? Values[i].fy : max.fy;
+					}
+				}
+			((Plot*)parent)->CheckBounds(min.fx, min.fy);
+			((Plot*)parent)->CheckBounds(max.fx, max.fy);
+			dirty = false;
+			return true;
+			}
+		return false;
+		}
+	return false;
+}
+
+void
+DataLine::SetValues()
+{
+	AccRange *rX, *rY1=0L, *rY2=0L;
+	int i, j, k, l, m, n;
+	double x, y;
+	char yref1[500], yref2[500];
+	lfPOINT *tmpValues = Values;
+
+	if(!ssXref || !ssYref) return;
+	if(!rlp_strcpy(yref1, 500, ssYref)) return;
+	for(i = 0, yref2[0] = 0; yref1[i]; i++) {
+		if(yref1[i] == ';') {
+			yref1[i++] = 0;
+			while(yref1[i] && yref1[i] < 33) i++;
+			rlp_strcpy(yref2, 500, yref1+i);
+			}
+		}
+	nPnt = nPntSet = 0;
+	min.fx = min.fy = HUGE_VAL;		max.fx = max.fy = -HUGE_VAL;
+	rX = new AccRange(ssXref);		rY1 = new AccRange(yref1);
+	if(!rX || !rY1){
+		if(rX) delete(rX);	if(rY1) delete(rY1);
+		return;
+		}
+	if(!name) name = rY1->RangeDesc(data, 1);
+	if(yref2[0] &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) {
+		if(!(Values = (lfPOINT *)realloc(Values, ((nPnt*2+2) * sizeof(lfPOINT))))) return; 
+		if(!(rY2 = new AccRange(yref2))) {
+			if(yref1) free(yref1);		if(yref2) free(yref2);
+			if(rX) delete(rX);	if(rY1) delete(rY1);
+			return;
+			}
+		if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && 
+			rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) &&
+			rY2->GetFirst(&m, &n) && rY2->GetNext(&m, &n)) do {
+			if(data->GetValue(j, i, &x)){
+				if(data->GetValue(l, k, &y)){
+					Values[nPntSet].fx = x;			Values[nPntSet++].fy = y;
+					}
+				if(data->GetValue(n, m, &y)){
+					Values[nPntSet].fx = x;			Values[nPntSet++].fy = y;
+					}
+				}
+			}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&m, &n));
+		}
+	else {
+		if((nPnt = rX->CountItems()) != (rY1->CountItems())) return;
+		if(!(Values = (lfPOINT *)realloc(Values, (nPnt+2) * sizeof(lfPOINT)))) return; 
+		if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && 
+			rX->GetNext(&i, &j) && rY1->GetNext(&k, &l)) do {
+			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+				Values[nPntSet].fx = x;				Values[nPntSet++].fy = y;
+				}
+			}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
+		}
+	nPnt = nPntSet;		nPntSet--;	dirty = true;
+	Command(CMD_AUTOSCALE, 0L, 0L);
+	if(tmpValues && Values != tmpValues) Undo.InvalidGO(this);
+	if(rX) delete(rX);	if(rY1) delete(rY1);	if(rY2) delete(rY2);
+}
+
+void
+DataLine::LineData(lfPOINT *val, long nval)
+{
+	lfPOINT *ov = Values;
+
+	if(!val || nval <2) return;
+	if(nval > nPnt && nPnt > 1 && Values){
+		if(!(Values = (lfPOINT *)realloc(Values, ((nval*2+2) * sizeof(lfPOINT))))) return; 
+		if(ov != Values) Undo.InvalidGO(this);
+		}
+	else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
+	memcpy(Values, val, nval * sizeof(lfPOINT));
+	if(pts) free(pts);			pts = 0L;				dirty = true;			
+	free(val);					nPnt = nval;				nPntSet = nPnt-1;
+}
+
+void
+DataLine::DrawCurve(anyOutput *target)
+{
+}
+
+void
+DataLine::DrawSpline(anyOutput *target)
+{
+	int i, j, k, klo, khi, ptsize = 1000;
+	double *y2, min, max, x, y, h, b, a;
+	POINT pn;
+	lfPOINT *scvals;
+	
+	if(!(y2 = (double*)malloc(sizeof(double)*(nPnt)))) return;
+	if(!(scvals = (lfPOINT*)malloc(sizeof(lfPOINT)*(nPnt)))){
+		free(y2);
+		return;
+		}
+	if((type & 0x0f) == 9 || (type & 0x0f) == 10) {
+		if((type & 0x0f) == 9) for(i = 0; i < nPnt; i++) {
+			scvals[i].fx = target->fx2fix(Values[i].fx);
+			scvals[i].fy = target->fy2fiy(Values[i].fy);
+			}
+		else for(i = 0; i < nPnt; i++) {
+			scvals[i].fy = target->fx2fix(Values[i].fx);
+			scvals[i].fx = target->fy2fiy(Values[i].fy);
+			}
+		SortFpArray(nPnt, scvals);
+		min = scvals[0].fx;			max = scvals[nPnt-1].fx;
+		for(i = j = 0; i < (nPnt-1); i++, j++) {
+			y = scvals[i].fy;			scvals[j].fx = scvals[i].fx;
+			for(k = 1; scvals[i+1].fx == scvals[i].fx; k++) {
+				y += scvals[i+1].fy;		i++;
+				}
+			scvals[j].fy = y/((double)k);
+			}
+		if(scvals[i].fx > scvals[i-1].fx) {
+			scvals[j].fx = scvals[i].fx;	scvals[j].fy = scvals[i].fy;
+			j++;
+			}
+		spline(scvals, j, y2);
+		h = scvals[1].fx - scvals[0].fx;	// klo and khi bracket the input value of x
+		for(x = min, klo = 0, i = khi = 1; x < max && i < j; x += 1.0) {
+			while(x > scvals[i].fx) {
+				klo++;		khi++;	i++;
+				h = scvals[khi].fx - scvals[klo].fx;
+				}
+			a = (scvals[khi].fx - x) / h;		b = (x - scvals[klo].fx) / h;
+			y = a * scvals[klo].fy + b * scvals[khi].fy + ((a*a*a - a) * y2[klo] + (b*b*b - b) * y2[khi]) * (h*h)/6.0;
+			if((type & 0x0f) == 9) {
+				pn.x = iround(x);		pn.y = iround(y);
+				}
+			else {
+				pn.x = iround(y);		pn.y = iround(x);
+				}
+			if(cp >= ptsize) {
+				ptsize += 1000;
+				pts = (POINT*)realloc(pts, sizeof(POINT)*ptsize); 
+				}
+			AddToPolygon(&cp, pts, &pn);
+			}
+		}
+	free(y2);	free(scvals);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// DataPolygon is a graphic object based on DataLine
+DataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange, char *nam):
+	DataLine(par, d, xrange, yrange, nam)
+{
+	lfPOINT *fp = Values;
+	char *rx = ssXref;
+	char *ry = ssYref;
+
+	FileIO(INIT_VARS);
+	Values = fp;				//FileIO will just set Values to 0L !
+	ssXref = rx;			ssYref = ry;
+	Id = GO_DATAPOLYGON;
+}
+
+DataPolygon::DataPolygon(int src):DataLine(0L, 0)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+DataPolygon::~DataPolygon()
+{
+	if(Values)free(Values);		Values =0L;
+	if(pts) free (pts);			pts = 0L;
+	if(ssXref) free(ssXref);	ssXref = 0L;
+	if(ssYref) free(ssYref);	ssYref = 0L;
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(name) free(name);		name = 0;
+	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+void
+DataPolygon::DoPlot(anyOutput *target)
+{
+	if(!Values || nPntSet < 2) return;
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	DataLine::DoPlot(target);	//no drawing but fill pts only
+	target->SetLine(&LineDef);	target->SetFill(&pgFill);
+	target->oPolygon(pts, cp);
+}
+
+void
+DataPolygon::DoMark(anyOutput *o, bool mark)
+{
+	if(pts && cp && o){
+		if(mark){
+			memcpy(&mrc, &rDims, sizeof(RECT));
+			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+			mo = GetRectBitmap(&mrc, o);
+			InvertPolygon(pts, cp, &LineDef, &pgFill, &mrc, o, mark);
+			}
+		else RestoreRectBitmap(&mo, &mrc, o);
+		}
+}
+
+bool
+DataPolygon::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	switch (cmd) {
+	case CMD_PG_FILL:
+		if(tmpl) {
+			memcpy((void*)&pgFill, tmpl, sizeof(FillDEF));
+			if(pgFill.hatch) memcpy((void*)&pgFillLine, (void*)pgFill.hatch, sizeof(LineDEF));
+			pgFill.hatch = (LineDEF*)&pgFillLine;
+			}
+		return true;
+	case CMD_SCALE:
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;			LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;		pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		break;
+	case CMD_LEGEND:
+		if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+			if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill, name);
+			}
+		break;
+	default:
+		return DataLine::Command(cmd, tmpl, o);
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a regression line
+// Ref.: "Biometry" third edition 1995 (ed. R.R. Sokal and F.J. Rohlf),
+// W.H. Freeman and Company, New York; ISBN 0-7167-2411-1; pp. 451ff
+RegLine::RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
+	GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	type = sel;
+	Id = GO_REGLINE;
+	uclip.Xmin = uclip.Ymin = lim.Xmin = lim.Ymin = -1.0;
+	uclip.Xmax = uclip.Ymax = lim.Xmax = lim.Ymax = 1.0;
+	Recalc(values, n);
+}
+
+RegLine::RegLine(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) FileIO(FILE_READ);
+}
+
+RegLine::~RegLine()
+{
+	if(pts) free(pts);		pts = 0L;
+	if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+double
+RegLine::GetSize(int select)
+{
+	double a, b;
+
+	switch(select) {
+	case SIZE_MX:		return mx;
+	case SIZE_MY:		return my;
+	case SIZE_A:
+	case SIZE_B:
+		switch(type & 0x07) {
+		case 1:		a = l2.fx;	b = l2.fy;	break;
+		case 2:		a = l3.fx;	b = l3.fy;	break;
+		case 3:		a = l4.fx;	b = l4.fy;	break;
+		case 4:		a = l5.fx;	b = l5.fy;	break;
+		default:	a = l1.fx;	b = l1.fy;	break;
+			}
+		if(select == SIZE_A) return a;
+		else return b;
+		}
+	return 0.0;
+}
+
+void
+RegLine::DoPlot(anyOutput *o)
+{
+	int i;
+	POINT pn;
+	double x, x1, y, d, a, b;
+	fRECT cliprc;
+	bool dValid;
+
+	switch (type & 0x70) {
+	case 0x20:	memcpy(&cliprc, &uclip, sizeof(fRECT));		break;
+	case 0x10:
+		if(parent) {
+			cliprc.Xmin = parent->GetSize(SIZE_BOUNDS_LEFT);
+			cliprc.Xmax = parent->GetSize(SIZE_BOUNDS_RIGHT);
+			cliprc.Ymin = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+			cliprc.Ymax = parent->GetSize(SIZE_BOUNDS_TOP);
+			break;
+			}
+		//no parent: use default
+	default:	memcpy(&cliprc, &lim, sizeof(fRECT));		break;
+		}
+	if(cliprc.Xmax < cliprc.Xmin) {
+		x = cliprc.Xmax;	cliprc.Xmax = cliprc.Xmin;	cliprc.Xmin = x;
+		}
+	if(cliprc.Ymax < cliprc.Ymin) {
+		y = cliprc.Ymax;	cliprc.Ymax = cliprc.Ymin;	cliprc.Ymin = y;
+		}
+	if(cliprc.Xmin == cliprc.Xmax || cliprc.Ymin == cliprc.Ymax) return;
+	if((!pts) && (!(pts = (POINT *)malloc(sizeof(POINT)*202))))return;
+	switch(type & 0x07) {
+	case 1:		a = l2.fx;	b = l2.fy;	break;
+	case 2:		a = l3.fx;	b = l3.fy;	break;
+	case 3:		a = l4.fx;	b = l4.fy;	break;
+	case 4:		a = l5.fx;	b = l5.fy;	break;
+	default:	a = l1.fx;	b = l1.fy;	break;
+		}
+	x = cliprc.Xmin;	d = (cliprc.Xmax - cliprc.Xmin)/200.0;
+	for (cp = i = 0; i <= 200; i++){
+		dValid = true;
+		switch(type & 0x700) {
+		case 0x100:					//logarithmic x
+			if(dValid = x > defs.min4log) x1 = log10(x);
+			break;
+		case 0x200:					//reciprocal x
+			if(dValid = fabs(x) > defs.min4log) x1 = 1.0/x;
+			break;
+		case 0x300:					//square root x
+			if(dValid = fabs(x) > defs.min4log) x1 = sqrt(x);
+			break;
+		default:	x1 = x;	break;		//linear x
+			}
+		y = a + b*x1;
+		if(dValid) switch(type & 0x7000) {
+		case 0x1000:				//logarithmic y
+			y = pow(10.0, y);
+			break;
+		case 0x2000:				//reciprocal y
+			if(dValid = fabs(y) >0.0001) y = 1.0/y;
+			break;
+		case 0x3000:				//square root y
+			if(dValid = fabs(y) >0.0001) y = y*y;
+			break;
+			}
+		if(dValid && y >= cliprc.Ymin && y <= cliprc.Ymax) {
+			pn.x = o->fx2ix(x);	pn.y = o->fy2iy(y);
+			AddToPolygon(&cp, pts, &pn);
+			}
+		x += d;
+		}
+	if(cp < 2) return;
+	o->SetLine(&LineDef);			o->oPolyline(pts, cp);
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+	i = 2*o->un2ix(LineDef.width);		//increase size of rectangle for marks
+	IncrementMinMaxRect(&rDims, i);
+}
+
+void
+RegLine::DoMark(anyOutput *o, bool mark)
+{
+	if(pts && cp && o){
+		if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
+		else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+		}
+}
+
+bool
+RegLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	POINT p1;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
+				return false; 
+			if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
+			}
+		break;
+	case CMD_SCALE:
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_REGLINE;
+		return true;
+	case CMD_BOUNDS:
+		if(tmpl) {
+			memcpy(&lim, tmpl, sizeof(fRECT));
+			memcpy(&uclip, tmpl, sizeof(fRECT));
+			}
+		return true;
+	case CMD_AUTOSCALE:
+		if(nPoints < 2) return false;
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
+			((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
+			return true;
+			}
+		return false;
+		}
+	return false;
+}
+
+void
+RegLine::Recalc(lfPOINT *values, long n)
+{
+	double sx, sy, dx, dy, sxy, sxx, syy;
+	double a, b, k;
+	long ic;
+
+	sx = sy = 0.0;
+	if((nPoints = n)<2) return;
+	for(ic = 0; ic < n; ic++) {
+		sx += values[ic].fx;		sy += values[ic].fy;
+		}
+	mx = sx /((double)nPoints);	my = sy/((double)nPoints);
+	sxy = sxx = syy = 0.0;
+	for(ic = 0; ic < n; ic++) {
+		dx = mx - values[ic].fx;	dy = my - values[ic].fy;
+		sxx += (dx*dx);	syy += (dy*dy);	sxy += (dx*dy);
+		}
+	l1.fy = sxy / sxx;			l1.fx = my - (sxy / sxx) * mx;
+	b = sxy / syy;				a = mx - (sxy / syy) * my;
+	l2.fy = 1.0/b;				l2.fx = -a / b;
+	l3.fy = (l1.fy+l2.fy)/2.0;	l3.fx = (l1.fx+l2.fx)/2.0;
+	l4.fy = sy/sx;				l4.fx = 0.0;
+	if(l5.fx == 0.0 && l5.fx == 0.0){
+		l5.fy = l1.fy;				l5.fx = l1.fx;
+		}
+	//calculate distance point from line algorithm
+	//Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
+	//   Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
+	//   pp. 47-48; ISBN 0-12-286165-5
+	k = (sqrt(1.0/(1.0+l1.fy*l1.fy))+sqrt(1.0/(1.0+l2.fy*l2.fy)))/2.0;
+	b = sqrt(1.0/(k*k) -1.0);
+	l3.fy = l3.fy > 0.0 ? b : -b;
+	l3.fx = my - mx * l3.fy;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a statnard deviation (SD-) ellipse
+SDellipse::SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
+	GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	type = sel;
+	Id = GO_SDELLIPSE;
+	if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT))){
+		memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
+		rl = new RegLine(this, data, values, n, type);
+		}
+}
+
+SDellipse::SDellipse(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) FileIO(FILE_READ);
+}
+
+SDellipse::~SDellipse()
+{
+	if(val) free(val);
+	if(pts) free(pts);
+	if(!(type & 0x10000) && parent && rl && 
+		parent->Command(CMD_DROP_OBJECT, rl, 0L)) return;
+	if(rl) DeleteGO(rl);
+}
+
+void
+SDellipse::DoPlot(anyOutput *o)
+{
+	int i;
+	double a1, b1, a2, b2, fv, k1, k2, ss1, ss2, np, x, dx, si, csi;
+	lfPOINT fp, fip;
+	POINT p1, *tmppts;
+
+	if(!rl) return;
+	if(pts) free(pts);
+	if(!(pts = (POINT *)malloc(sizeof(POINT)*420)))return;
+	//get line data from regression line object
+	mx = rl->GetSize(SIZE_MX);		my = rl->GetSize(SIZE_MY);
+	a1 = rl->GetSize(SIZE_A);		b1 = rl->GetSize(SIZE_B);
+	b2 = -1.0/b1;	a2 = my - b2 * mx;
+	//calculate sine and cosine for back rotation
+	fv = sqrt(1.0+b1*b1);			si = b1/fv;			csi = 1.0/fv;
+	//calculate distance from line for each point and squared sum of distances
+	//Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
+	//   Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
+	//   pp. 47-48; ISBN 0-12-286165-5
+	k1 = sqrt(1.0/(1.0+b1*b1));			k2 = sqrt(1.0/(1.0+b2*b2));
+	// y = a + b*x;
+	ss1 = ss2 = 0.0;
+	for(i = 0; i < nPoints; i++) {
+		fv = (a1 + b1 * val[i].fx - val[i].fy) * k1;	ss1 += (fv*fv);
+		fv = (a2 + b2 * val[i].fx - val[i].fy) * k2;	ss2 += (fv*fv);
+		}
+	np = ((double)(nPoints-1));
+	//SD perpendicular and in direction of regression line
+	sd1 = sqrt(ss1 /= np);		sd2 = sqrt(ss2 /= np);
+	dx = sd2/100.0;
+	for(i = 0, cp = 0, x = -sd2; i < 2; i++) {
+		do {
+			fv = (x*x)/ss2;
+			fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1) : 0.0;
+			fv = i ? fv : -fv;
+			fp.fx = mx + x * csi - fv * si;
+			fp.fy = my + x * si + fv * csi;
+			switch(type & 0x700) {
+			case 0x100:					//logarithmic x
+				fp.fx = pow(10.0, fp.fx);
+				break;
+			case 0x200:					//reciprocal x
+				if(fabs(fp.fx) > defs.min4log) fp.fx = 1.0/fp.fx;
+				else fp.fx = 0.0;
+				break;
+			case 0x300:					//square root x
+				if(fabs(fp.fx) > defs.min4log) fp.fx = fp.fx*fp.fx;
+				else fp.fx = 0.0;
+				break;
+				}
+			switch(type & 0x7000) {
+			case 0x1000:				//logarithmic y
+				fp.fy = pow(10.0, fp.fy);
+				break;
+			case 0x2000:				//reciprocal y
+				if(fabs(fp.fy) > defs.min4log) fp.fy = 1.0/fp.fy;
+				else fp.fy = 0.0;
+				break;
+			case 0x3000:				//square root y
+				if(fabs(fp.fy) > defs.min4log) fp.fy = fp.fy*fp.fy;
+				else fp.fy = 0.0;
+				break;
+				}
+			o->fp2fip(&fp, &fip);	p1.x = iround(fip.fx);		p1.y = iround(fip.fy);
+			AddToPolygon(&cp, pts, &p1);
+			}while((x += dx) < sd2 && x > -sd2);
+		x = sd2;
+		dx *= -1.0;
+		}
+	o->SetLine(&LineDef);
+	if(cp > 2) {
+		AddToPolygon(&cp, pts, pts);		//close polygon
+		if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
+		SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+		for(i = 2; i < cp; i++) 
+			UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&rDims, i);
+		o->oPolyline(pts, cp);
+		}
+	else {
+		free(pts);
+		cp = 0;
+		}
+	if(!(type & 0x10000))rl->DoPlot(o);
+}
+
+void
+SDellipse::DoMark(anyOutput *o, bool mark)
+{
+	if(pts && cp && o){
+		if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
+		else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+		}
+}
+
+bool
+SDellipse::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	POINT p1;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!(type & 0x10000) && rl && rl->Command(cmd, tmpl, o)) return true;
+			if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
+				return false; 
+			if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
+			}
+		break;
+	case CMD_SCALE:
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		if(rl) rl->Command(cmd, tmpl, o);
+		break;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_RMU:
+		if(!(type & 0x10000) && parent && rl && parent->Command(CMD_DROP_OBJECT, rl, o)){
+			rl = 0L;
+			return true;
+			}
+		return false;
+	case CMD_INIT:
+		if(rl) return rl->PropertyDlg();
+		break;
+	case CMD_DROP_OBJECT:
+		if(tmpl && ((GraphObj*)tmpl)->Id == GO_REGLINE && !rl) {
+			rl = (RegLine *)tmpl;
+			rl->parent = this;
+			return true;
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_SDELLIPSE;
+		if(rl) rl->Command(cmd, tmpl, o);
+		return true;
+	case CMD_BOUNDS:
+		if(tmpl) {
+			if(rl) rl->Command(cmd, tmpl, o);
+			memcpy(&lim, tmpl, sizeof(fRECT));
+			}
+		return true;
+	case CMD_DELOBJ:
+		if(tmpl && tmpl == (void*)rl) {
+			Undo.ValInt(parent, &type, 0L);
+			type |= 0x10000;
+			if(parent) parent->Command(CMD_REDRAW, 0L, o);
+			return true;
+			}
+		break;
+	case CMD_AUTOSCALE:
+		if(nPoints < 2) return false;
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
+			((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+void
+SDellipse::Recalc(lfPOINT *values, long n)
+{
+	if(val) free(val);
+	if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT)))
+		memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
+	if(rl) rl->Recalc(values, n);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Error bars are simple graphic objects
+ErrorBar::ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int which,
+	int xc, int xr, int yc, int yr, int ec, int er):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	fPos.fx = x;		fPos.fy = y;
+	ferr = err;
+	type = which;
+	Id = GO_ERRBAR;
+	data = d;
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || ec >= 0 || er >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = ec;	ssRef[2].y = er;
+			cssRef = 3;
+			}
+		}
+	Command(CMD_AUTOSCALE, 0L, 0L);
+}
+
+ErrorBar::ErrorBar(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	type = ERRBAR_VSYM;
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+ErrorBar::~ErrorBar()
+{
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(name) free(name);		name = 0L;
+}
+
+bool
+ErrorBar::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_ERRBAR: 
+		SizeBar = value;
+		return true;
+	case SIZE_ERRBAR_LINE:
+		ErrLine.width = value;
+		return true;
+		}
+	return false;
+}
+
+bool
+ErrorBar::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_ERROR_LINE:
+		ErrLine.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+ErrorBar::DoPlot(anyOutput *target)
+{
+	int ie;
+
+	switch (type & 0x0ff) {
+	case ERRBAR_VSYM:
+	case ERRBAR_VUP:
+	case ERRBAR_VDOWN:
+		ie = target->un2ix(SizeBar/2.0);
+		break;
+	default:
+		ie = target->un2iy(SizeBar/2.0);
+		break;
+		}
+	target->SetLine(&ErrLine);
+	switch(type) {
+	case ERRBAR_VSYM:
+		ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
+		ebpts[0].y = target->fy2iy(fPos.fy-ferr);
+		ebpts[4].y = ebpts[5].y = ebpts[1].y = target->fy2iy(fPos.fy+ferr);
+		if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
+		ebpts[4].x = ebpts[2].x = ebpts[0].x - ie;
+		ebpts[5].x = ebpts[3].x = ebpts[1].x + ie+1;
+		ebpts[2].y = ebpts[3].y = ebpts[0].y;
+		if(ebpts[3].x > ebpts[2].x) {
+			target->oSolidLine(ebpts+2);
+			target->oSolidLine(ebpts+4);
+			}
+		rDims.left =  ebpts[2].x;		rDims.right = ebpts[3].x;
+		rDims.top = ebpts[0].y;			rDims.bottom = ebpts[1].y;
+		break;
+	case ERRBAR_VUP:
+	case ERRBAR_VDOWN:
+		ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
+		ebpts[0].y = target->fy2iy(fPos.fy);
+		ebpts[2].y = ebpts[3].y = ebpts[1].y = 
+			target->fy2iy(type == ERRBAR_VUP ? fPos.fy+ferr : fPos.fy-ferr);
+		if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
+		ebpts[2].x = ebpts[0].x - ie;
+		ebpts[3].x = ebpts[1].x + ie+1;
+		if(ebpts[3].x > ebpts[2].x) target->oSolidLine(ebpts+2);
+		rDims.left =  ebpts[2].x;		rDims.right = ebpts[3].x;
+		rDims.top = ebpts[0].y;			rDims.bottom = ebpts[1].y;
+		break;
+	case ERRBAR_HSYM:
+		ebpts[2].x = ebpts[3].x = ebpts[0].x = target->fx2ix(fPos.fx-ferr);
+		ebpts[4].x = ebpts[5].x = ebpts[1].x = target->fx2ix(fPos.fx+ferr);
+		ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
+		if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
+		ebpts[2].y = ebpts[4].y = ebpts[0].y - ie;
+		ebpts[3].y = ebpts[5].y = ebpts[1].y + ie+1;
+		if(ebpts[3].y >ebpts[2].y) {
+			target->oSolidLine(ebpts+2);
+			target->oSolidLine(ebpts+4);
+			}
+		rDims.left =  ebpts[0].x;		rDims.right = ebpts[1].x;
+		rDims.top = ebpts[2].y;			rDims.bottom = ebpts[3].y;
+		break;
+	case ERRBAR_HLEFT:
+	case ERRBAR_HRIGHT:
+		ebpts[0].x = target->fx2ix(fPos.fx);
+		ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
+		ebpts[2].x = ebpts[3].x = ebpts[1].x = 
+			target->fx2ix(type == ERRBAR_HRIGHT ? fPos.fx+ferr : fPos.fx-ferr);
+		if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
+		ebpts[2].y = ebpts[0].y - ie;
+		ebpts[3].y = ebpts[1].y + ie+1;
+		if(ebpts[3].y > ebpts[2].y) target->oSolidLine(ebpts+2);
+		rDims.left =  ebpts[0].x;		rDims.right = ebpts[1].x;
+		rDims.top = ebpts[2].y;			rDims.bottom = ebpts[3].y;
+		break;
+		}
+	if(rDims.left > rDims.right) Swap(rDims.left, rDims.right);
+	if(rDims.top > rDims.bottom) Swap(rDims.top, rDims.bottom);
+	IncrementMinMaxRect(&rDims, 2);
+}
+
+void
+ErrorBar::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+	LineDEF OldLine;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
+		i = 3*o->un2ix(ErrLine.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
+		ErrLine.width *= 5.0;				DoPlot(o);
+		ErrLine.width = OldLine.width;		ErrLine.color = OldLine.color ^ 0x00ffffffL;
+		DoPlot(o);							o->UpdateRect(&mrc, false);
+		memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	bool bFound;
+	int cb;
+
+	switch (cmd) {
+	case CMD_SCALE:
+		ErrLine.width *= ((scaleINFO*)tmpl)->sy.fy;		ErrLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		SizeBar *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		bFound = false;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!IsInRect(&rDims, mev->x, mev->y) || CurrGO) return false; 
+			switch (type) {
+			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
+				if(mev->y >= (ebpts[0].y-2) && mev->y <= (ebpts[1].y+2)) bFound = true;
+				else if(mev->x >= (ebpts[2].x-2) && mev->x <= (ebpts[2].x+2)) bFound = true;
+				else if(type == ERRBAR_HSYM && mev->x >= (ebpts[4].x-2) &&
+					mev->x <= (ebpts[4].x + 2)) bFound = true;
+				break;
+			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
+				if(mev->x >= (ebpts[0].x-2) && mev->x <= (ebpts[1].x+2)) bFound = true;
+				else if(mev->y >= (ebpts[2].y-2) && mev->y <= (ebpts[2].y+2)) bFound = true;
+				else if(type == ERRBAR_VSYM && mev->y >= (ebpts[4].y-2) &&
+					mev->y <= (ebpts[4].y + 2)) bFound = true;
+				break;
+				}
+			if(bFound) o->ShowMark(this, MRK_GODRAW);
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_ERRBAR;
+		data = (DataObj *) tmpl;
+		return true;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >2 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &ferr);
+			return true;
+			}
+		return false;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		switch(type) {
+			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
+				((Legend*)tmpl)->HasErr(&ErrLine, 1, name);
+				break;
+			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
+				((Legend*)tmpl)->HasErr(&ErrLine, 2, name);
+				break;
+			}
+		break;
+	case CMD_ERRDESC:
+		if(tmpl && *((char *)tmpl)){
+			cb = (int)strlen((char*)tmpl)+2;
+			if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
+			return true;
+			}
+		return false;
+	case CMD_ERR_TYPE:
+		if(tmpl) type = *((int*)tmpl);
+		return true;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			switch(type) {
+			case ERRBAR_VSYM:	
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr);
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr);		break;
+			case ERRBAR_VUP:	
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr);		break;
+			case ERRBAR_VDOWN:
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr);		break;
+			case ERRBAR_HSYM:
+				((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
+				((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy);		break;
+			case ERRBAR_HLEFT:
+				((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy);
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);				break;
+			case ERRBAR_HRIGHT:
+				((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
+				((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);				break;
+				}
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// arrows to data points or with absolute coordinates
+Arrow::Arrow(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2, int yc2, int yr2):
+	GraphObj(par, d)
+{
+	double dx, dy;
+
+	FileIO(INIT_VARS);
+	memcpy(&pos1, &fp1, sizeof(lfPOINT));
+	memcpy(&pos2, &fp2, sizeof(lfPOINT));
+	type = which;
+	if(type & ARROW_UNITS) {
+		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+		pos1.fx -= dx;	pos1.fy -= dy;			pos2.fx -= dx;	pos2.fy -= dy;
+		}
+	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
+		yc2 >= 0 || yr2 >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+			ssRef[0].x = xc1;	ssRef[0].y = xr1;
+			ssRef[1].x = yc1;	ssRef[1].y = yr1;
+			ssRef[2].x = xc2;	ssRef[2].y = xr2;
+			ssRef[3].x = yc2;	ssRef[3].y = yr2;
+			cssRef = 4;
+			}
+		}
+	bModified = false;
+}
+
+Arrow::Arrow(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+Arrow::~Arrow()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+	if(bModified) Undo.InvalidGO(this);
+}
+
+double
+Arrow::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XPOS:		return pos1.fx;
+	case SIZE_XPOS+1:	return pos2.fx;
+	case SIZE_YPOS:		return pos1.fy;
+	case SIZE_YPOS+1:	return pos2.fy;
+	case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
+	case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
+		if(parent) return parent->GetSize(select);
+		break;
+		}
+	return 0.0;
+}
+
+bool
+Arrow::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_ARROW_LINE:		LineDef.width = value;		return true;
+	case SIZE_ARROW_CAPWIDTH:	cw = value;					return true;
+	case SIZE_ARROW_CAPLENGTH:	cl = value;					return true;
+	case SIZE_XPOS:				pos1.fx = value;			return true;
+	case SIZE_XPOS+1:			pos2.fx = value;			return true;
+	case SIZE_YPOS:				pos1.fy = value;			return true;
+	case SIZE_YPOS+1:			pos2.fy = value;			return true;
+		}
+	return false;
+}
+
+bool
+Arrow::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_ARROW:
+		LineDef.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+Arrow::DoPlot(anyOutput *o)
+{
+	double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
+
+	if(!o || !parent) return;
+	if(type & ARROW_UNITS) {
+		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+		fix1 = o->co2fix(pos1.fx+dx);	fix2 = o->co2fix(pos2.fx+dx);
+		fiy1 = o->co2fiy(pos1.fy+dy);	fiy2 = o->co2fiy(pos2.fy+dy);
+		}
+	else {
+		fix1 = o->fx2fix(pos1.fx);		fix2 = o->fx2fix(pos2.fx);
+		fiy1 = o->fy2fiy(pos1.fy);		fiy2 = o->fy2fiy(pos2.fy);
+		}
+	if(fix1 == fix2 && fiy1 == fiy2) return;	//zero length
+	//draw arrow line
+	pts[0].x = iround(fix1);		pts[1].x = iround(fix2);
+	pts[0].y = iround(fiy1);		pts[1].y = iround(fiy2);
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	//calculate sine and cosine for cap
+	si = fiy1-fiy2;
+	tmp = fix2 - fix1;
+	si = si/sqrt(si*si + tmp*tmp);
+	csi = fix2-fix1;
+	tmp = fiy2 - fiy1;
+	csi = csi/sqrt(csi*csi + tmp*tmp);
+	//draw cap
+	pts[2].x = pts[1].x - o->un2ix(csi*cl + si*cw/2.0);
+	pts[2].y = pts[1].y + o->un2iy(si*cl - csi*cw/2.0);
+	pts[3].x = pts[1].x;		pts[3].y = pts[1].y;
+	pts[4].x = pts[1].x - o->un2ix(csi*cl - si*cw/2.0);
+	pts[4].y = pts[1].y + o->un2iy(si*cl + csi*cw/2.0);
+	switch(type & 0xff) {
+	case ARROW_NOCAP:
+		pts[2].x = pts[3].x = pts[4].x = pts[1].x;
+		pts[2].y = pts[3].y = pts[4].y = pts[1].y;
+		break;
+		}
+	UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
+	UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+	IncrementMinMaxRect(&rDims, 3);
+	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+	else Redraw(o);
+}
+
+void
+Arrow::DoMark(anyOutput *o, bool mark)
+{
+	LineDEF OldLine;
+
+	if(type & ARROW_UNITS) {
+		if(!dh1) dh1 = new dragHandle(this, DH_12);
+		if(!dh2) dh2 = new dragHandle(this, DH_22);
+		}
+	else {
+		if (dh1) DeleteGO(dh1);		if (dh2) DeleteGO(dh2);
+		dh1 = dh2 = 0L;
+		}
+	memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+	if(mark) {
+		LineDef.color = 0x00000000L;
+		LineDef.width = OldLine.width *3.0;
+		Redraw(o);
+		LineDef.width = OldLine.width;
+		LineDef.color = OldLine.color ^ 0x00ffffffL;
+		Redraw(o);
+		if(dh1) dh1->DoPlot(o);		if(dh2) dh2->DoPlot(o);
+		}
+	else if(parent){
+		LineDef.color = 0x00ffffffL;
+		LineDef.width = OldLine.width *3.0;
+		Redraw(o);
+		LineDef.width = OldLine.width;
+		LineDef.color = OldLine.color;
+		parent->DoPlot(o);
+		}
+	memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+	o->UpdateRect(&rDims, false);
+}
+
+bool
+Arrow::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_SAVEPOS:
+		bModified = true;
+		Undo.SaveLFP(this, &pos1, 0L);
+		Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
+		return true;
+	case CMD_SCALE:
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		cw *= ((scaleINFO*)tmpl)->sy.fy;				cl *= ((scaleINFO*)tmpl)->sy.fy;
+		if(type & ARROW_UNITS) {
+			pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
+			pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
+			pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
+			pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
+			}
+		return true;
+	case CMD_FLUSH:
+		if (dh1) DeleteGO(dh1);			dh1 = 0L;
+		if (dh2) DeleteGO(dh2);			dh2 = 0L;
+		if(ssRef) free(ssRef);			ssRef = 0L;
+		if(name) free(name);			name = 0L;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+		if(!CurrGO && ObjThere(mev->x, mev->y)){
+			o->ShowMark(this, MRK_GODRAW);
+			return true;
+			}
+		}
+		break;
+	case CMD_ARROW_ORG:
+		memcpy(&pos1, tmpl, sizeof(lfPOINT));
+		if(ssRef && cssRef >3) 
+			ssRef[0].x = ssRef[0].y = ssRef[1].x = ssRef[1].y = -1;
+		return true;
+	case CMD_ARROW_TYPE:
+		if(tmpl) {
+			type &= ~0xff;		type |= (*((int*)tmpl));
+			return true;
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_ARROW;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >3 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+			((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+			return true;
+			}
+		break;
+	case CMD_MRK_DIRTY:			//from Undo ?
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_MOVE:
+		bModified = true;
+	case CMD_UNDO_MOVE:
+		if(type & ARROW_UNITS) {
+			if(cmd == CMD_MOVE) Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+			pos1.fx += ((lfPOINT*)tmpl)[0].fx;	pos1.fy += ((lfPOINT*)tmpl)[0].fy;
+			pos2.fx += ((lfPOINT*)tmpl)[0].fx;	pos2.fy += ((lfPOINT*)tmpl)[0].fy;
+			if(o){
+				o->StartPage();		parent->DoPlot(o);		o->EndPage();
+				}
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+void
+Arrow::Redraw(anyOutput *o)
+{
+	FillDEF FillCap;
+
+	o->SetLine(&LineDef);
+	o->oSolidLine(pts);
+	switch(type & 0xff) {
+	case ARROW_NOCAP:
+		break;
+	case ARROW_LINE:
+		o->oSolidLine(pts+2);
+		o->oSolidLine(pts+3);
+		break;
+	case ARROW_TRIANGLE:
+		FillCap.type = FILL_NONE;
+		FillCap.color = LineDef.color;
+		FillCap.scale = 1.0f;
+		FillCap.hatch = 0L;
+		o->SetFill(&FillCap);
+		o->oPolygon(pts+2, 3);
+		break;
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// universal boxes
+Box::Box(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
+		int yc2, int yr2):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	memcpy(&pos1, &fp1, sizeof(lfPOINT));
+	memcpy(&pos2, &fp2, sizeof(lfPOINT));
+	type = which;
+	Id = GO_BOX;
+	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
+		yc2 >= 0 || yr2 >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+			ssRef[0].x = xc1;	ssRef[0].y = xr1;
+			ssRef[1].x = yc1;	ssRef[1].y = yr1;
+			ssRef[2].x = xc2;	ssRef[2].y = xr2;
+			ssRef[3].x = yc2;	ssRef[3].y = yr2;
+			cssRef = 4;
+			}
+		}
+}
+
+Box::Box(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+Box::~Box()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Box::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XPOS:
+		return (pos1.fx + pos2.fx)/2.0;
+	case SIZE_YPOS:
+		return (pos1.fy + pos2.fy)/2.0;
+		}
+	return 1.0;
+}
+
+bool
+Box::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_BOX_LINE:		Outline.width = value;		return true;
+	case SIZE_BOX:			size = value;				return true;
+	case SIZE_XPOS:			pos1.fx = value;			return true;
+	case SIZE_XPOS+1:		pos2.fx = value;			return true;
+	case SIZE_YPOS:			pos1.fy = value;			return true;
+	case SIZE_YPOS+1:		pos2.fy = value;			return true;
+		}
+	return false;
+}
+
+bool
+Box::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_BOX_LINE:
+		Outline.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+Box::DoPlot(anyOutput *o)
+{
+	double si, csi, tmp, fix1, fiy1, fix2, fiy2, fsize, dx, dy;
+
+	if(!parent || !o || size <= 0.001) return;
+	o->SetLine(&Outline);
+	o->SetFill(&Fill);
+	//calculate coordinates
+	fix1 = o->fx2fix(pos1.fx);	fix2 = o->fx2fix(pos2.fx);
+	fiy1 = o->fy2fiy(pos1.fy);	fiy2 = o->fy2fiy(pos2.fy);
+	//calculate sine and cosine
+	si = fiy1-fiy2;
+	tmp = fix2 - fix1;
+	si = si/sqrt(si*si + tmp*tmp);
+	csi = fix2-fix1;
+	tmp = fiy2 - fiy1;
+	csi = csi/sqrt(csi*csi + tmp*tmp);
+	if(type & BAR_WIDTHDATA) {			//use e.g. for density distribution
+		dx = si * size;					dy = csi * size;
+		pts[0].x = o->fx2ix(pos1.fx + dx);	pts[1].x = o->fx2ix(pos2.fx + dx);
+		pts[2].x = o->fx2ix(pos2.fx - dx);	pts[3].x = o->fx2ix(pos1.fx - dx);
+		pts[0].y = o->fy2iy(pos1.fy + dy);	pts[1].y = o->fy2iy(pos2.fy + dy);
+		pts[2].y = o->fy2iy(pos2.fy - dy);	pts[3].y = o->fy2iy(pos1.fy - dy);
+		}
+	else if(type & BAR_RELWIDTH) {
+		if(!parent || (pos1.fy == pos2.fy && pos1.fx == pos2.fx)) return;
+		fsize = parent->GetSize(pos1.fy == pos2.fy ? SIZE_BOXMINY : SIZE_BOXMINX);
+		fsize = fsize * size /200.0;
+		dx = si * fsize;					dy = csi * fsize;
+		pts[0].x = o->fx2ix(pos1.fx + dx);	pts[1].x = o->fx2ix(pos2.fx + dx);
+		pts[2].x = o->fx2ix(pos2.fx - dx);	pts[3].x = o->fx2ix(pos1.fx - dx);
+		pts[0].y = o->fy2iy(pos1.fy + dy);	pts[1].y = o->fy2iy(pos2.fy + dy);
+		pts[2].y = o->fy2iy(pos2.fy - dy);	pts[3].y = o->fy2iy(pos1.fy - dy);
+		}
+	else {
+		dx = o->un2fix(si*size/2.0);		dy = o->un2fiy(csi*size/2.0);
+		pts[0].x = iround(fix1 + dx);	pts[1].x = iround(fix2 + dx);
+		pts[2].x = iround(fix2 - dx);	pts[3].x = iround(fix1 - dx);
+		pts[0].y = iround(fiy1 + dy);	pts[1].y = iround(fiy2 + dy);
+		pts[2].y = iround(fiy2 - dy);	pts[3].y = iround(fiy1 - dy);
+		}
+	pts[4].x = pts[0].x;		pts[4].y = pts[0].y;	//close polygon
+	if(pts[0].x == pts[1].x){
+		o->oRectangle(pts[3].x, pts[3].y, pts[1].x, pts[1].y, name);
+		}
+	else {
+		o->oPolygon(pts, 5);
+		}
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[2].x, pts[2].y);
+	UpdateMinMaxRect(&rDims, pts[1].x, pts[1].y);
+	UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+}
+
+void
+Box::DoMark(anyOutput *o, bool mark)
+{
+	InvertPolygon(pts, 5, &Outline, &Fill, &rDims, o, mark);
+}
+
+bool
+Box::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	POINT p;
+
+	switch (cmd) {
+	case CMD_SCALE:
+		Outline.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Hatchline.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		if(!(type & BAR_RELWIDTH) && parent->Id!= GO_DENSDISP)size *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_FLUSH:
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name)free(name);			name = 0L;
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		((Legend*)tmpl)->HasFill(&Outline, &Fill, name);
+		break;
+	case CMD_MRK_DIRTY:				case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
+					o->ShowMark(CurrGO = this, MRK_GODRAW);
+					return true;
+					}
+				else {
+					p.x = mev->x;		p.y = mev->y;
+					if(IsInPolygon(&p, pts, 5)) {
+						o->ShowMark(CurrGO = this, MRK_GODRAW);
+						return true;
+						}
+					}
+				}
+			break;
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_BOX;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >3 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+			return true;
+			}
+		return false;
+	case CMD_BOX_TYPE:
+		if(tmpl)type = *((int*)tmpl);
+		return true;
+	case CMD_BOX_FILL:
+		if(tmpl) {
+			memcpy(&Fill, tmpl, sizeof(FillDEF));
+			if(Fill.hatch) memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
+			Fill.hatch = &Hatchline;
+			return true;
+			}
+		break;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			if(type & BAR_WIDTHDATA) {
+				if(pos1.fy != pos2.fy) {
+					((Plot*)parent)->CheckBounds(pos1.fx+size, pos1.fy);
+					((Plot*)parent)->CheckBounds(pos2.fx-size, pos2.fy);
+					}
+				else {
+					((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy+size);
+					((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy-size);
+					}
+				}
+			else {
+				((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+				((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+				if(parent && (type & BAR_RELWIDTH)) {
+					if(pos1.fy == pos2.fy) {
+						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy + parent->GetSize(SIZE_BOXMINY));
+						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy - parent->GetSize(SIZE_BOXMINY));
+						}
+					else if(pos1.fx == pos2.fx) {
+						((Plot*)parent)->CheckBounds(pos2.fx + parent->GetSize(SIZE_BOXMINX), pos2.fy);
+						((Plot*)parent)->CheckBounds(pos2.fx - parent->GetSize(SIZE_BOXMINX), pos2.fy);
+						}
+					}
+				}
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// whisker 
+Whisker::Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+	int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
+	int yc2, int yr2):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	memcpy(&pos1, &fp1, sizeof(lfPOINT));
+	memcpy(&pos2, &fp2, sizeof(lfPOINT));
+	type = which;
+	Id = GO_WHISKER;
+	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 || 
+		yc2 >= 0 || yr2 >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+			ssRef[0].x = xc1;	ssRef[0].y = xr1;
+			ssRef[1].x = yc1;	ssRef[1].y = yr1;
+			ssRef[2].x = xc2;	ssRef[2].y = xr2;
+			ssRef[3].x = yc2;	ssRef[3].y = yr2;
+			cssRef = 4;
+			}
+		}
+	Command(CMD_AUTOSCALE, 0L, 0L);
+}
+
+Whisker::Whisker(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+Whisker::~Whisker()
+{
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(name) free(name);		name = 0L;
+}
+
+bool
+Whisker::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_WHISKER: 
+		size = value;
+		return true;
+	case SIZE_WHISKER_LINE:
+		LineDef.width = value;
+		return true;
+		}
+	return false;
+}
+
+bool
+Whisker::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_WHISKER:
+		LineDef.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+Whisker::DoPlot(anyOutput *o)
+{
+	double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
+	int i;
+
+	fix1 = o->fx2fix(pos1.fx);	fix2 = o->fx2fix(pos2.fx);
+	fiy1 = o->fy2fiy(pos1.fy);	fiy2 = o->fy2fiy(pos2.fy);
+	if(fix1 == fix2 && fiy1 == fiy2) return;	//zero length
+	pts[2].x = iround(fix1);		pts[3].x = iround(fix2);
+	pts[2].y = iround(fiy1);		pts[3].y = iround(fiy2);
+	//calculate sine and cosine
+	si = fiy1-fiy2;
+	tmp = fix2 - fix1;
+	si = si/sqrt(si*si + tmp*tmp);
+	csi = fix2-fix1;
+	tmp = fiy2 - fiy1;
+	csi = csi/sqrt(csi*csi + tmp*tmp);
+	dx = o->un2fix(si*size/2.0);
+	dy = o->un2fiy(csi*size/2.0);
+	//calc cap
+	pts[0].x = iround(fix1 - dx);	pts[4].x = iround(fix2 - dx);
+	pts[0].y = iround(fiy1 - dy);	pts[4].y = iround(fiy2 - dy);
+	pts[1].x = iround(fix1 + dx);	pts[5].x = iround(fix2 + dx);
+	pts[1].y = iround(fiy1 + dy);	pts[5].y = iround(fiy2 + dy);
+	//draw whisker
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+	UpdateMinMaxRect(&rDims, pts[5].x, pts[5].y);
+	IncrementMinMaxRect(&rDims, 3+(o->un2ix(LineDef.width)<<1));
+	o->SetLine(&LineDef);
+	switch(type & 0x0f) {
+	case 2:
+		pts[4].x = pts[3].x;	pts[4].y = pts[3].y;
+		pts[1].x = pts[2].x;	pts[1].y = pts[2].y;
+	case 3:
+		if((type & 0x0f) == 3){
+			pts[5].x = pts[3].x;	pts[5].y = pts[3].y;
+			pts[0].x = pts[2].x;	pts[0].y = pts[2].y;
+			}
+	case 0:
+		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+		break;
+	case 1:
+		pts[4].x = pts[5].x = pts[3].x;		pts[4].y = pts[5].y = pts[3].y;
+		pts[1].x = pts[0].x = pts[2].x;		pts[1].y = pts[0].y = pts[2].y;
+		o->oSolidLine(pts+2);
+		break;
+		}
+}
+
+void
+Whisker::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+	LineDEF OldLine;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
+		LineDef.width *= 5.0;				DoPlot(o);
+		LineDef.width = OldLine.width;		LineDef.color = OldLine.color ^ 0x00ffffffL;
+		DoPlot(o);							o->UpdateRect(&mrc, false);
+		memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Whisker::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	int cb;
+
+	switch (cmd) {
+	case CMD_SCALE:
+		size *= ((scaleINFO*)tmpl)->sy.fy;
+		LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
+		LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				if(IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y) ||
+					IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
+					IsCloseToLine(&pts[4], &pts[5], mev->x, mev->y)) {
+						o->ShowMark(this, MRK_GODRAW);
+						return true;
+						}
+				}
+			break;
+			}
+		return false;
+	case CMD_ERRDESC:
+		if(tmpl && *((char*)tmpl)) {
+			cb = (int)strlen((char*)tmpl)+2;
+			if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
+			return true;
+			}
+		return false;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		switch(type & 0x0f) {
+		case 1:		((Legend*)tmpl)->HasErr(&LineDef, 5, name);		break;
+		case 2:		((Legend*)tmpl)->HasErr(&LineDef, 4, name);		break;
+		case 3:		((Legend*)tmpl)->HasErr(&LineDef, 3, name);		break;
+		default:
+			if((rDims.right - rDims.left) < (rDims.bottom - rDims.top))
+				((Legend*)tmpl)->HasErr(&LineDef, 1, name);
+			else ((Legend*)tmpl)->HasErr(&LineDef, 2, name);
+			break;
+			}
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_WHISKER;		data = (DataObj *)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >3 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+			((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+			return true;
+			}
+		break;
+	case CMD_WHISKER_STYLE:
+		if(tmpl) type = *((int*)tmpl);
+		return true;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// drop line 
+DropLine::DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc, 
+	int xr, int yc, int yr):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	fPos.fx = x;
+	fPos.fy = y;
+	type = which;
+	Id = GO_DROPLINE;
+	if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			cssRef = 2;
+			}
+		}
+	bModified = false;
+}
+
+DropLine::DropLine(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+DropLine::~DropLine()
+{
+	if(bModified) Undo.InvalidGO(this);
+	if(ssRef) free(ssRef);		ssRef = 0L;
+}
+
+void
+DropLine::DoPlot(anyOutput *o)
+{
+	int tmp;
+
+	o->RLP.fp = 0.0f;		//reset line pattern start
+	if(parent) {
+		pts[0].x = pts[1].x = pts[2].x = pts[3].x = o->fx2ix(fPos.fx);
+		pts[0].y = pts[1].y = pts[2].y = pts[3].y = o->fy2iy(fPos.fy);
+		if(type & DL_LEFT) {
+			tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_LEFT));
+			if(tmp < pts[0].x) pts[0].x = tmp;
+			if(tmp > pts[1].x) pts[1].x = tmp;
+			}
+		if(type & DL_RIGHT) {
+			tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_RIGHT));
+			if(tmp < pts[0].x) pts[0].x = tmp;
+			if(tmp > pts[1].x) pts[1].x = tmp;
+			}
+		if(type & DL_YAXIS) {
+			tmp = iround(parent->GetSize(SIZE_YAXISX));
+			if(tmp < pts[0].x) pts[0].x = tmp;
+			if(tmp > pts[1].x) pts[1].x = tmp;
+			}
+		if(type & DL_TOP) {
+			tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_TOP));
+			if(tmp < pts[2].y) pts[2].y = tmp;
+			if(tmp > pts[3].y) pts[3].y = tmp;
+			}
+		if(type & DL_BOTTOM) {
+			tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_BOTTOM));
+			if(tmp < pts[2].y) pts[2].y = tmp;
+			if(tmp > pts[3].y) pts[3].y = tmp;
+			}
+		if(type & DL_XAXIS) {
+			tmp = iround(parent->GetSize(SIZE_XAXISY));
+			if(tmp < pts[2].y) pts[2].y = tmp;
+			if(tmp > pts[3].y) pts[3].y = tmp;
+			}
+		SetMinMaxRect(&rDims, pts[0].x, pts[2].y, pts[1].x, pts[3].y);
+		IncrementMinMaxRect(&rDims, 3);
+		o->SetLine(&LineDef);
+		o->oPolyline(pts, 2);
+		o->oPolyline(pts+2, 2);
+		}
+}
+
+void
+DropLine::DoMark(anyOutput *o, bool mark)
+{
+
+	InvertLine(pts, 2, &LineDef, 0L, o, mark);
+	InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
+}
+
+bool
+DropLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				if(IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
+					IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y)) {
+					o->ShowMark(this, MRK_GODRAW);
+					return true;
+					}
+				}
+			break;
+			}
+		return false;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_DL_LINE:
+		if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+		return true;
+	case CMD_DL_TYPE:
+		if(tmpl)type = *((int*)tmpl);
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_DROPLINE;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >1 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define a spherical scanline used for clipping spheres
+sph_scanline::sph_scanline(POINT3D *center, int radius, bool bVert):GraphObj(0, 0)
+{
+	Id = GO_SPHSCANL;
+	rad = radius >= 0 ? radius : -radius;
+	memcpy(&p1, center, sizeof(POINT3D));	memcpy(&p2, center, sizeof(POINT3D));
+	memcpy(&cent, center, sizeof(POINT3D));
+	if(vert = bVert) {
+		p1.y -= rad;		p2.y += rad;
+		}
+	else {
+		p1.x -= rad;		p2.x += rad;
+		}
+	if(p1.x < 1) p1.x = 1;			if(p1.y < 1) p1.y = 1;
+	if(p2.x < p1.x) p2.x = p1.x;	if(p2.y < p1.y) p2.y = p1.y;
+	bValid1 = bValid2 = true;
+}
+
+bool
+sph_scanline::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	switch(cmd) {
+	case CMD_ADDTOLINE:
+		if(bValid1 && tmpl){
+			memcpy(&p2, tmpl, sizeof(POINT3D));
+			bValid2 = true;
+			return true;
+			}
+		break;
+	case CMD_STARTLINE:
+		if(!bValid1 && tmpl){
+			memcpy(&p1, tmpl, sizeof(POINT3D));
+			bValid1 = true;
+			}
+		break;
+		return true;
+		}
+	return false;
+}
+
+void
+sph_scanline::DoClip(GraphObj *co)
+{
+	POINT3D *pla;
+	int np, i;
+
+	if(!bValid1 || !bValid2) return;
+	switch(co->Id){
+	case GO_SPHERE:
+		bValid1 = bValid2 = false;
+		clip_sphline_sphere(this, &p1, &p2, &cent, rad, iround(co->GetSize(SIZE_RADIUS1)), 
+			iround(co->GetSize(SIZE_XPOS)), iround(co->GetSize(SIZE_YPOS)), 
+			iround(co->GetSize(SIZE_ZPOS)));
+		break;
+	case GO_PLANE:
+		for(i=0; ((plane*)co)->GetPolygon(&pla, &np, i); i++) {
+			bValid1 = bValid2 = false;
+			clip_sphline_plane(this, &p1, &p2, &cent, rad, pla, np, ((plane*)co)->GetVec());
+			}
+		break;
+		}
+}
+	
+bool
+sph_scanline::GetPoint(POINT *p, int sel)
+{
+	if(!bValid1 || !bValid2) {
+		p->x = p->y = 0;
+		return false;
+		}
+	switch(sel) {
+	case 1:
+		p->x = p1.x;	p->y = p1.y;
+		return true;
+	case 2:
+		p->x = p2.x;	p->y = p2.y;
+		return true;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Sphere: a symbol in three dimensional space
+Sphere::Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z, 
+	double r, int xc, int xr, int yc, int yr, int zc, int zr, int rc, int rr)
+	:GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	Id = GO_SPHERE;
+	fPos.fx = x;	fPos.fy = y;	fPos.fz = z;	size = r;
+	if(xc >=0 || xr >=0 || yc >=0 || yr >=0 || zc >=0 || zr >=0 || rc >=0 || rr >=0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = zc;	ssRef[2].y = zr;
+			ssRef[3].x = rc;	ssRef[3].y = rr;
+			cssRef = 4;
+			}
+		}
+	type = sel;
+	bModified = false;
+}
+
+Sphere::Sphere(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+Sphere::~Sphere()
+{
+	if(bModified) Undo.InvalidGO(this);
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Sphere::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_MIN_X:		return fip.fx - (double)rx;
+	case SIZE_MAX_X:		return fip.fx + (double)rx;
+	case SIZE_MIN_Y:		return fip.fy - (double)ry;
+	case SIZE_MAX_Y:		return fip.fy + (double)ry;
+	case SIZE_MIN_Z:		return fip.fz - (double)rx;
+	case SIZE_MAX_Z:		return fip.fz + (double)rx;
+	case SIZE_XPOS:			return fip.fx;
+	case SIZE_YPOS:			return fip.fy;
+	case SIZE_ZPOS:			return fip.fz;
+	case SIZE_RADIUS1:	case SIZE_RADIUS2:	return (double)rx;
+	case SIZE_XCENT:		return fPos.fx;
+	case SIZE_YCENT:		return fPos.fy;
+	case SIZE_ZCENT:		return fPos.fz;
+	case SIZE_DRADIUS:		return size;
+	case SIZE_SYMBOL:
+		if(!type) return size;
+		else return DefSize(SIZE_SYMBOL);
+	case SIZE_SYM_LINE:		return Line.width;
+		}
+	return 0.0;
+}
+
+bool
+Sphere::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_SYMBOL:		size = value;			break;
+	case SIZE_SYM_LINE:		Line.width = value;		break;
+		}
+	return true;
+}
+
+DWORD
+Sphere::GetColor(int select)
+{
+	switch(select) {
+	case COL_SYM_LINE:		return Line.color;
+	case COL_SYM_FILL:		return Fill.color;
+	default: return defs.Color(select);
+		}
+}
+
+bool
+Sphere::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_SYM_LINE:		Line.color = col;		break;
+	case COL_SYM_FILL:		Fill.color = col;		break;
+		}
+	return true;
+}
+
+void
+Sphere::DoPlot(anyOutput *o)
+{
+	int i;
+
+	if(size <= 0.001 || !o) return;
+	if(!o->fvec2ivec(&fPos, &fip)) return;
+	bDrawDone = false;
+	if(scl){
+		for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
+		free(scl);
+		scl = 0L;	nscl = 0;
+		}
+	ix = iround(fip.fx);			iy = iround(fip.fy);
+	switch (type) {
+	case 1:
+		rx = ry = iround(size * 0.5 * o->ddx);		break;
+	case 2:
+		rx = ry = iround(size * 0.5 * o->ddy);		break;
+	case 3:
+		rx = ry = iround(size * 0.5 * o->ddz);		break;
+	default:
+		type = 0;
+	case 5:
+		rx = o->un2ix(size/2.0);	ry = o->un2iy(size/2.0);
+		break;
+		}
+	rDims.left = ix - rx;			rDims.right = ix + rx;
+	rDims.top = iy - ry;			rDims.bottom = iy + ry;
+	if(o->VPscale > 1.5 && (
+		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+		bDrawDone = true;		return;
+		}
+	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+	Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Sphere::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	int i;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name) free(name);		name = 0L;
+		if(scl){
+			for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
+			free(scl);
+			scl = 0L;	nscl = 0;
+			}
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		if(!type || type == 5)size *= ((scaleINFO*)tmpl)->sy.fy;;
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+		break;
+	case CMD_SYM_FILL:
+		if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
+		return true;
+	case CMD_MRK_DIRTY:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_SPHERE;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_REDRAW:
+		//Note: this command is issued either by Undo (no output given) or
+		//  by Plot3D::DoPlot after sorting all objects (output specified)
+		if(!parent) return false;
+		if(!o) return parent->Command(cmd, tmpl, o);
+		if(bDrawDone) return false;
+		bDrawDone = true;
+		if(scl) DrawPG(o, 0);
+		else {
+			o->SetLine(&Line);				o->SetFill(&Fill);
+			if(Fill.type & FILL_LIGHT3D) o->oSphere(ix, iy, rx, 0L, 0, 0L);
+			else o->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+			}
+		rx--;ry--;			//smaller marking rectangle
+		rDims.left = ix-rx-1;				rDims.right = ix+rx+1;
+		rDims.top = iy-ry-1;				rDims.bottom = iy+ry+1;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				o->ShowMark(&rDims, MRK_INVERT);
+				CurrGO = this;
+				return true;
+				}
+			break;
+			}
+		break;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >1 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+			if(cssRef >3) data->GetValue(ssRef[3].y, ssRef[3].x, &size);
+			return true;
+			}
+		return false;
+	case CMD_CLIP:
+		if(co = (GraphObj*)tmpl){
+			switch(co->Id) {
+			case GO_PLANE:
+			case GO_SPHERE:
+				DoClip(co);
+				break;
+				}
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+void
+Sphere::DoClip(GraphObj *co)
+{
+	RECT cliprc;
+	double d, d1;
+	POINT3D cscl;
+	int x, y, q, di, de, lim, cx, cy;
+	int i;
+
+	if(co && co->Id == GO_SPHERE) {
+		if(co->GetSize(SIZE_ZPOS) > fip.fz) return;
+		d1 = (d = co->GetSize(SIZE_XPOS) - fip.fx) * d;
+		d1 += (d = co->GetSize(SIZE_YPOS) - fip.fy) * d;
+		d1 = sqrt(d1 + (d = co->GetSize(SIZE_ZPOS) - fip.fz) * d);
+		if(d1 >= (co->GetSize(SIZE_RADIUS1) + rx))return;
+		}
+	else {
+		cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+		cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+		cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+		cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+		if(!OverlapRect(&rDims, &cliprc))return;
+		}
+	//use a list of horizontal scanlines created by a circular Bresenham's algorithm
+	//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+	//   Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.; 
+	//   ISBN 0-12-288165-5 
+	if(!scl && (scl = (sph_scanline**)calloc(rx*7+2, sizeof(sph_scanline*)))) {
+		cscl.z = iround(fip.fz);			nscl = 0;
+		for(q = 0; q < 2; q++) {
+			x = lim = 0;	y = rx;		di = 2*(1-rx);
+			while( y >= lim) {
+				if(di < 0) {
+					de = 2*di + 2*y -1;
+					if(de > 0) {
+						x++;	y--;	di += (2*x -2*y +2);
+						}
+					else {
+						x++;	di += (2*x +1);
+						}
+					}
+				else {
+					de = 2*di -2*x -1;
+					if(de > 0) {
+						y--;	di += (-2*y +1);
+						}
+					else {
+						x++;	y--;	di += (2*x -2*y +2);
+						}
+					}
+				switch(q) {
+				case 0:
+					cy = rx - y;			cx = x;
+					break;
+				case 1:
+					cy = rx + x;			cx = y; 
+					break;
+					}
+				cscl.y = iround(fip.fy);		cscl.x = iround(fip.fx);
+				cscl.y = cscl.y - rx + cy;
+				if(cx > 1) scl[nscl++] = new sph_scanline(&cscl, cx, false);
+				}
+			}
+		}
+	if(!scl) return;
+	//do clip for every scanline
+	for(i = 0; i < nscl; i++) if(scl[i]) scl[i]->DoClip(co);
+}
+
+void
+Sphere::DrawPG(anyOutput *o, int start)
+{
+	POINT *pts, np;
+	long cp = 0;
+	int i = start, step = 1;
+
+	if(!o || !scl ||!nscl) return;
+	if((pts = (POINT*)calloc(nscl*2, sizeof(POINT)))) {
+		do {
+			if(scl[i]) {
+				if(step > 0) scl[i]->GetPoint(&np, 1);
+				else scl[i]->GetPoint(&np, 2);
+				if(np.x && np.y){
+					AddToPolygon(&cp, pts, &np);
+					}
+				else if(cp){
+					if(step > 0) DrawPG(o, i);			//split sphere
+					step = -1;
+					}
+				}
+			if(i == nscl && step > 0) step = -1;
+			else i += step;
+			}while(i > start);
+		}
+	o->SetLine(&Line);				o->SetFill(&Fill);
+	if(cp) o->oSphere(ix, iy, rx, pts, cp, name);
+	free(pts);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// plane: utility object to draw a flat plane in 3D space
+plane::plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line, 
+	  FillDEF *fill):GraphObj(par, d)
+{
+	int i;
+	long area;
+	double vlength, v1[3], v2[3], vp[3], area1;
+	bool v_valid = false;
+	
+	nli = n_ipts = n_lines = 0;
+	nldata = 0L;  ldata = 0L;	co = 0L;	lines = 0L;		PlaneVec = 0L;
+	Id = GO_PLANE;	totalArea = 0;
+	memcpy(&Line, line, sizeof(LineDEF));
+	memcpy(&Fill, fill, sizeof(FillDEF));
+	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
+	if(nPts > 2 && (ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
+		(ldata[0] = (POINT3D *)calloc(nPts+1, sizeof(POINT3D))) &&
+		(nldata = (int*)calloc(1, sizeof(int)))	&&
+		(ipts = (POINT*)calloc(nPts, sizeof(POINT)))){
+		for(i = 0; i < nPts; i++) {
+			ipts[i].x = ldata[0][i].x = iround(pts[i].fx);
+			ipts[i].y = ldata[0][i].y = iround(pts[i].fy);
+			ldata[0][i].z = iround(pts[i].fz);
+			}
+		nldata[0] = nPts;		nli = 1;	n_ipts = nPts;
+		xBounds.fx = xBounds.fy = pts[0].fx;	yBounds.fx = yBounds.fy = pts[0].fy;
+		zBounds.fx = zBounds.fy = pts[0].fz;
+		rDims.left = rDims.right = ipts[0].x;	rDims.top = rDims.bottom = ipts[0].y;
+		for(i = 1; i < nPts; i++){
+			UpdateMinMaxRect(&rDims, ipts[i].x, ipts[i].y);
+			if(pts[i].fx < xBounds.fx) xBounds.fx = pts[i].fx;
+			if(pts[i].fx > xBounds.fy) xBounds.fy = pts[i].fx;
+			if(pts[i].fy < yBounds.fx) yBounds.fx = pts[i].fy;
+			if(pts[i].fy > yBounds.fy) yBounds.fy = pts[i].fy;
+			if(pts[i].fz < zBounds.fx) zBounds.fx = pts[i].fz;
+			if(pts[i].fz > zBounds.fy) zBounds.fy = pts[i].fz;
+			}
+		//test if plane vertical
+		area1 = (xBounds.fx - xBounds.fy) * (yBounds.fx - yBounds.fy);
+		for(area = 0, i = 1; i < nPts; i++) {
+			area += (ipts[i].x - ipts[i-1].x) * ((ipts[i].y + ipts[i-1].y)>>1);
+			}
+		totalArea= area = abs(area);
+		area1 = area ? fabs(area1/area) : 101.0;
+		if(area < 100 && area1 > 100.0) {			//its small or vertical !
+			if(lines=(line_segment**)calloc(nPts, sizeof(line_segment*))){
+				for(i = 1; i < nPts; i++) {
+					lines[i-1] = new line_segment(par, d, line, &ldata[0][i-1], &ldata[0][i]);
+					}
+				n_lines = nPts-1;
+				}
+			}
+		else {					//for a visible plane get vector perpendicular to plane
+			for (i = 1; i < (nPts-1); i++) {
+				v1[0] = pts[i].fx - pts[i-1].fx;	v1[1] = pts[i].fy - pts[i-1].fy;
+				v1[2] = pts[i].fz - pts[i-1].fz;	v2[0] = pts[i+1].fx - pts[i].fx;
+				v2[1] = pts[i+1].fy - pts[i].fy;	v2[2] = pts[i+1].fz - pts[i].fz;
+				vp[0] = v1[1]*v2[2] - v1[2]*v2[1];	vp[1] = v1[2]*v2[0] - v1[0]*v2[2];
+				vp[2] = v1[0]*v2[1] - v1[1]*v2[0];
+				vlength = sqrt(vp[0]*vp[0]+vp[1]*vp[1]+vp[2]*vp[2]);
+				if(v_valid = (vlength > 100.0)) break;
+				}
+			if(v_valid && (PlaneVec = (double*)malloc(4 * sizeof(double)))) {
+				PlaneVec[0] = vp[0]/vlength;		PlaneVec[1] = vp[1]/vlength;
+				PlaneVec[2] = -vp[2]/vlength;
+				PlaneVec[3] = PlaneVec[0] * pts[i].fx + PlaneVec[1] * pts[i].fy - PlaneVec[2] * pts[i].fz;
+				}
+			}
+		}
+}
+
+plane::~plane() 
+{
+	int i;
+
+	if(ldata) {
+		for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
+		free(ldata);	ldata = 0L;		nli = 0;
+		}
+	if(lines) {
+		for(i = 0; i < n_lines; i++) if(lines[i]) delete(lines[i]);
+		free(lines);	lines = 0L;		n_lines = 0;
+		}
+	if(nldata) free(nldata);		nldata = 0L;
+	if(ipts) free(ipts);			ipts = 0L;
+	if(PlaneVec) free(PlaneVec);	PlaneVec = 0L;
+}
+
+double
+plane::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_MIN_X:		return xBounds.fx;
+	case SIZE_MAX_X:		return xBounds.fy;
+	case SIZE_MIN_Y:		return yBounds.fx;
+	case SIZE_MAX_Y:		return yBounds.fy;
+	case SIZE_MIN_Z:		return zBounds.fx;
+	case SIZE_MAX_Z:		return zBounds.fy;
+		}
+	return 0.0;
+}
+
+void
+plane::DoPlot(anyOutput *o)
+{
+	int i;
+
+	bDrawDone = bReqPoint = false;
+	if(Fill.type & FILL_LIGHT3D){
+		Fill.color = o->VecColor(PlaneVec, Fill.color2, Fill.color);
+		Fill.type &= ~FILL_LIGHT3D;
+		}
+	if(o->VPscale > 1.5 && (
+		//ignore objects outside the display ara
+		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+		bDrawDone = true;		return;
+		}
+	if(lines) {
+		if(Line.width == 0.0) return;
+		//draw line segments for vertical plane
+		for(i = 0; i < n_lines; i++) if(lines[i]) lines[i]->DoPlot(o);
+		bDrawDone = true;		return;
+		}
+	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+	Command(CMD_REDRAW, 0L, o);
+}
+
+void
+plane::DoMark(anyOutput *o, bool mark)
+{
+	FillDEF tmpfill;
+	LineDEF tmpline;
+
+	memcpy(&tmpfill, &Fill, sizeof(FillDEF));
+	memcpy(&tmpline, &Line, sizeof(LineDEF));
+	if(mark){
+		tmpfill.color ^= 0x00ffffffL;		tmpline.color ^= 0x00ffffffL;
+		}
+	o->SetLine(&tmpline);					o->SetFill(&tmpfill);
+	o->oPolygon(ipts, n_ipts);
+}
+
+bool 
+plane::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	POINT *pt;
+	POINT3D *ap;
+	int i, j;
+	
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_REDRAW:
+		if(bDrawDone) return false;
+		bDrawDone = true;
+		if(o && nldata){
+			if(Line.width == 0.0) Line.color = Fill.color;
+			o->SetLine(&Line);			o->SetFill(&Fill);
+			for(i = 0; i < nli; i++){
+				if(nldata[i] > 2 && (pt = (POINT*)malloc(nldata[i]*sizeof(POINT)))){
+					for(j = 0; j < nldata[i]; j++) {
+						pt[j].x = ldata[i][j].x;	pt[j].y = ldata[i][j].y;
+						}
+					o->oPolygon(pt, nldata[i]);
+					free(pt);
+					}
+				}
+			}
+		return true;
+	case CMD_STARTLINE:
+		if(ap = (POINT3D*)tmpl) {
+			if(ldata && nldata && nli) {
+				if(bReqPoint) {
+					Command(CMD_ADDTOLINE, &ReqPoint, o);
+					bReqPoint = false;
+					}
+				i = nli-1;			j = nldata[i]-1;
+				if(ldata[i][j].x == ap->x && ldata[i][j].y == ap->y && ldata[i][j].z == ap->z){
+					return true;
+					}
+				if(IsValidPG(ldata[i], nldata[i])) {
+					//close previous polygon first
+					if(ldata[i][0].x != ldata[i][j].x || ldata[i][0].y != ldata[i][j].y ||
+						ldata[i][0].z != ldata[i][j].z){
+						j++;
+						ldata[i][j].x = ldata[i][0].x;	ldata[i][j].y = ldata[i][0].y;
+						ldata[i][j].z = ldata[i][0].z;	nldata[i]++;
+						}
+					ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
+					ldata[nli] = (POINT3D*)malloc(sizeof(POINT3D)*2);
+					nldata = (int*)realloc(nldata, sizeof(int) * (nli+1));
+					}
+				else {					//drop incomplete or invalid polygon
+					nli--;
+					}
+				}
+			else {
+				ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
+				ldata[nli = 0] = (POINT3D*)malloc(sizeof(POINT3D));
+				nldata = (int*)calloc(1, sizeof(int));
+				bReqPoint = false;
+				}
+			if(ldata && nldata) {
+				ldata[nli][0].x = ap->x;	ldata[nli][0].y = ap->y;
+				ldata[nli][0].z = ap->z;	nldata[nli++] = 1;
+				return true;
+				}
+			}
+		break;
+	case CMD_REQ_POINT:
+		if(ap = (POINT3D*)tmpl) {
+			ReqPoint.x = ap->x;		ReqPoint.y = ap->y;		ReqPoint.z = ap->z;
+			bReqPoint = true;
+			}
+		return true;
+	case CMD_ADDTOLINE:
+		if((ap = (POINT3D*)tmpl) && ldata && nldata && nli) {
+			i= nli-1;	j=nldata[i]-1;
+			if((ldata[i][j].x == ap->x && ldata[i][j].y == ap->y) ||
+				(ldata[i][j].y == ap->y && ldata[i][j].z == ap->z)){
+				//probably nothing to add
+				ldata[i][j].x = ap->x;			ldata[i][j].y = ap->y;
+				return j>0 ? true : false;
+				}
+			ldata[i] = (POINT3D*)realloc(ldata[i], ((j=nldata[i])+2) * sizeof(POINT3D));
+			ldata[i][j].x = ap->x;			ldata[i][j].y = ap->y;
+			ldata[i][j].z = ap->z;			nldata[i]++;
+			return true;
+			}
+	case CMD_CLIP:
+		if(co = (GraphObj*)tmpl){
+			switch(co->Id) {
+			case GO_PLANE:
+				//Clip only planes which are drawn later
+				if(GetSize(SIZE_MIN_Z) < co->GetSize(SIZE_MIN_Z)) return false;
+				if(nli){
+					DoClip(co);
+					if(nli && ldata) {
+						i = nli-1;			j = nldata[i]-1;
+						//is last part valid ?
+						if(j < 2) {
+							free(ldata[i]);		ldata[i] = 0L;
+							nldata[i] = 0;
+							nli--;
+							}
+						//close last polygon
+						else if(ldata[i][0].x != ldata[i][j].x ||
+							ldata[i][0].y != ldata[i][j].y ||
+							ldata[i][0].z != ldata[i][j].z){
+							j++;
+							ldata[i][j].x = ldata[i][0].x;
+							ldata[i][j].y = ldata[i][0].y;
+							ldata[i][j].z = ldata[i][0].z;
+							nldata[i]++;
+							}
+						}
+					}
+				else xBounds.fx=xBounds.fy=yBounds.fx=yBounds.fy=zBounds.fx=zBounds.fy=0.0;
+				break;
+				}
+			}
+		break;
+		}
+	return false;
+}
+
+void * 
+plane::ObjThere(int x, int y)
+{
+	POINT p1;
+
+	if(bDrawDone && IsInRect(&rDims, p1.x = x, p1.y = y) &&
+		(IsInPolygon(&p1, ipts, n_ipts) || IsCloseToPL(p1, ipts, n_ipts))) return this;
+	return 0L;
+}
+
+bool
+plane::GetPolygon(POINT3D **pla, int *npt, int n)
+{
+	if(n < nli && ldata && ldata[n]) {
+		*pla = ldata[n];	*npt = nldata[n];
+		return true;
+		}
+	return false;
+}
+
+void
+plane::DoClip(GraphObj *co)
+{
+	RECT cliprc;
+	int o_nli, *o_nldata = 0L;
+	POINT3D **o_ldata = 0L;
+	POINT3D *tpg;
+	int i, j, tnpt;
+	bool is_valid = false;
+
+	//if two planes have the same parent it means they are part of one object
+	// do not clip!
+	if(co->parent == parent && co->Id == GO_PLANE) return;
+	if(co->Id == GO_PLANE && (parent->parent->Id == GO_GRID3D || parent->parent->Id == GO_RIBBON)
+		&& co->parent->parent == parent->parent) return;
+	cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+	cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+	cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+	cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+	if(OverlapRect(&rDims, &cliprc) && co != this) {
+		o_nli = nli;		nli = 0;
+		o_nldata = nldata;	nldata = 0L;
+		o_ldata = ldata;	ldata = 0L;
+		switch(co->Id) {
+		case GO_PLANE:
+			//clip all parts of this plane with all from another plane
+			for(i = 0; ((plane*)co)->GetPolygon(&tpg, &tnpt, i); i++){
+				for(j = 0; j < o_nli; j++) {
+					if(o_nldata[j] >2) clip_plane_plane(this, o_ldata[j], o_nldata[j], PlaneVec, 
+						tpg, tnpt, ((plane*)co)->GetVec(), ipts, n_ipts );
+					}
+				if(bReqPoint){
+					Command(CMD_ADDTOLINE, &ReqPoint, 0L);
+					bReqPoint = false;
+					}
+				if(nli) is_valid = true;
+				if(o_ldata) {
+					for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
+					free(o_ldata);
+					}
+				if(o_nldata) free(o_nldata);
+				o_nli = nli;		nli = 0;
+				o_nldata = nldata;	nldata = 0L;
+				o_ldata = ldata;	ldata = 0L;
+				if(!o_nli) {					//plane is completly hidden
+					return;
+					}
+				}
+			if(is_valid || i==0){
+				nli = o_nli;		o_nli = 0;
+				nldata = o_nldata;	o_nldata = 0L;
+				ldata = o_ldata;	o_ldata = 0L;
+				}
+			if(nli > 1) for(i = 1; i < nli; i++) {
+				if(nldata[i] > 3 && ldata[i][nldata[i]-1].x == ldata[i-1][0].x
+					&& ldata[i][nldata[i]-1].y == ldata[i-1][0].y) {
+					nldata[i]--;	//bad vis: ignore last point
+					}
+				}
+			break;
+		default:
+			nli = o_nli;		o_nli = 0;
+			nldata = o_nldata;	o_nldata = 0L;
+			ldata = o_ldata;	o_ldata = 0L;
+			break;
+			}
+		//check shape and recalc some values
+		if(is_valid && nli) {
+			xBounds.fx = xBounds.fy = ldata[0][0].x;	yBounds.fx = yBounds.fy = ldata[0][0].y;
+			zBounds.fx = zBounds.fy = ldata[0][0].z;
+			rDims.left = rDims.right = ldata[0][0].x;	rDims.top = rDims.bottom = ldata[0][0].y;
+			for(i = 0; i < nli; i++) if(nldata[i] > 2){
+				if(ldata[i][0].x != ldata[i][nldata[i]-1].x || ldata[i][0].y != ldata[i][nldata[i]-1].y
+					|| ldata[i][0].z != ldata[i][nldata[i]-1].z) {
+					ldata[i][nldata[i]].x = ldata[i][0].x;	ldata[i][nldata[i]].y = ldata[i][0].y;
+					ldata[i][nldata[i]].z = ldata[i][0].z;	nldata[i]++;
+					}
+				for(j = 0; j < (nldata[i]-1); j++) {
+					UpdateMinMaxRect(&rDims, ldata[i][j].x, ldata[i][j].y);
+					if(ldata[i][j].x < xBounds.fx) xBounds.fx = ldata[i][j].x;
+					if(ldata[i][j].x > xBounds.fy) xBounds.fy = ldata[i][j].x;
+					if(ldata[i][j].y < yBounds.fx) yBounds.fx = ldata[i][j].y;
+					if(ldata[i][j].y > yBounds.fy) yBounds.fy = ldata[i][j].y;
+					if(ldata[i][j].z < zBounds.fx) zBounds.fx = ldata[i][j].z;
+					if(ldata[i][j].z > zBounds.fy) zBounds.fy = ldata[i][j].z;
+					}
+				}
+			}
+		}
+	if(o_ldata) {
+		for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
+		free(o_ldata);
+		}
+	if(o_nldata) free(o_nldata);
+}
+
+bool
+plane::IsValidPG(POINT3D *pg, int npg)
+{
+	int i;
+	long area;
+
+	//a polygon must have more than 3 Points
+	if(npg < 3) return false;
+	//check for a reasonable size
+	for(area = 0, i = 1; i < npg; i++) {
+		area += (pg[i].x - pg[i-1].x) * ((pg[i].y + pg[i-1].y)>>1);
+		}
+	area += (pg[0].x - pg[i-1].x) * ((pg[0].y + pg[i-1].y)>>1);
+	area = abs(area);
+	if(area < 20) return false;
+	if(totalArea/area > 100) return false;
+	return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a simple plane in three dimensional space
+Plane3D::Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt)
+	:GraphObj(par, da) 
+{
+	FileIO(INIT_VARS);
+	Id = GO_PLANE3D;
+	dt = (fPOINT3D*) memdup(pt, sizeof(fPOINT3D)*npt, 0L);
+	ndt = npt;
+}
+
+Plane3D::Plane3D(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+Plane3D::~Plane3D()
+{
+	if(dt) free(dt);	if(pts) free(pts);
+	dt = 0L;		ndt = 0L;
+	if(ipl) delete (ipl);	ipl = 0L;
+}
+
+bool
+Plane3D::SetSize(int select, double value)
+{
+	int i;
+
+	if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <=  SIZE_XPOS_LAST){
+		if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)ndt){
+			dt[i].fx = value;			return true;
+			}
+		}
+	else if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
+		if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)ndt){
+			dt[i].fy = value;			return true;
+			}
+		}
+	else if((select & 0xfff) >= SIZE_ZPOS && (select & 0xfff) <= SIZE_ZPOS_LAST){
+		if((i = select-SIZE_ZPOS) >=0 && i <= 200 && i < (int)ndt){
+			dt[i].fz = value;			return true;
+			}
+		}
+	else switch(select) {
+	case SIZE_SYM_LINE:
+		Line.width = value;
+		}
+	return false;
+}
+
+bool
+Plane3D::SetColor(int select, DWORD col)
+{
+	switch(select) {
+	case COL_POLYLINE:		Line.color = col;		return true;
+	case COL_POLYGON:		Fill.color = col;		return true;
+		}
+	return false;
+}
+
+void
+Plane3D::DoPlot(anyOutput *o)
+{
+	int i;
+
+	if(ipl) delete ipl;		ipl = 0L;
+	if(pts) free(pts);		pts = 0L;
+	o->ActualSize(&rDims);
+	rDims.left = rDims.right;	rDims.top = rDims.bottom;
+	rDims.right = rDims.bottom = 0;
+	if((pts = (fPOINT3D*)malloc(sizeof(fPOINT3D)*ndt))){
+		for(i = 0; i < ndt; i++) {
+			if(!o->fvec2ivec(&dt[i], &pts[i])){
+				free(pts);	pts = 0L; return;
+				}
+			UpdateMinMaxRect(&rDims, iround(pts[i].fx), iround(pts[i].fy));
+			}
+		if(ipl = new plane(this, data, pts, i, &Line, &Fill))ipl->DoPlot(o);
+		}
+	IncrementMinMaxRect(&rDims, o->un2ix(Line.width)+1);
+}
+
+void
+Plane3D::DoMark(anyOutput *o, bool mark)
+{
+	if(mark){
+		if(pts && ipl)ipl->DoMark(o, mark);
+		o->UpdateRect(&rDims, false);
+		}
+	else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Plane3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i;
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_SET_DATAOBJ:
+		Id = GO_PLANE3D;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+		break;
+	case CMD_MRK_DIRTY:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_SYM_FILL:
+		if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
+		return true;
+	case CMD_REDRAW:
+		//Note: this command is issued either by Undo (no output given) or
+		//  by Plot3D::DoPlot after sorting all objects (output specified)
+		if(!parent) return false;
+		if(!o) return parent->Command(cmd, tmpl, o);
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				if(ipl && ipl->ObjThere(mev->x, mev->y)){
+					o->ShowMark(CurrGO=this, MRK_GODRAW);
+					return true;
+					}
+				}
+			break;
+			}
+		break;
+	case CMD_PG_FILL:
+		if(tmpl) {
+			memcpy((void*)&Fill, tmpl, sizeof(FillDEF));
+			Fill.hatch = 0L;
+			}
+		break;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && dt) {
+			for(i = 0; i < ndt; i++)
+				((Plot*)parent)->CheckBounds3D(dt[i].fx, dt[i].fy, dt[i].fz);
+			return true;
+			}
+		break;
+	case CMD_SET_GO3D:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Brick: a bar in three dimensional space
+Brick::Brick(GraphObj *par, DataObj *da, double x, double y, double z, 
+		double d, double w, double h, DWORD flg, int xc, int xr, int yc,
+		int yr, int zc, int zr, int dc, int dr, int wc, int wr, int hc,
+		int hr):GraphObj(par, da)
+{
+	FileIO(INIT_VARS);
+	Id = GO_BRICK;
+	fPos.fx = x;	fPos.fy = y;	fPos.fz = z;
+	depth = d;		width = w;		height = h;
+	flags = flg;
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0 ||
+		dc >= 0 || dr >= 0 || wc >= 0 || wr >= 0 || hc >= 0 || hr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = zc;	ssRef[2].y = zr;
+			ssRef[3].x = dc;	ssRef[3].y = dr;
+			ssRef[4].x = wc;	ssRef[4].y = wr;
+			ssRef[5].x = hc;	ssRef[5].y = hr;
+			cssRef = 6;
+			}
+		}
+	bModified = false;
+}
+
+Brick::Brick(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+	
+Brick::~Brick()
+{
+	int i;
+
+	if(faces) {
+		for(i = 0; i < 6; i++) if(faces[i]) delete(faces[i]);
+		free(faces);
+		}
+	faces = 0L;
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	Command(CMD_FLUSH, 0L, 0L);
+	if(bModified) Undo.InvalidGO(this);
+}
+
+bool
+Brick::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_BAR_LINE:		Line.width = value;		return true;
+	case SIZE_BAR_BASE:		fPos.fy = value;		return true;
+	case SIZE_BAR:			width = value;			return true;
+	case SIZE_BAR_DEPTH:	depth = value;			return true;
+		}
+	return false;
+}
+
+bool
+Brick::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_BAR_LINE:		Line.color = col;		return true;
+	case COL_BAR_FILL:		Fill.color = col;		return true;
+		}
+	return false;
+}
+
+void
+Brick::DoPlot(anyOutput *o)
+{
+	fPOINT3D cpt[8], fip1, fip2, tmp, itmp, *pg;
+	plane *npl;
+	double dtmp;
+	int i;
+
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	if(!faces || !o || !o->fvec2ivec(&fPos, &fip1)) return;
+	if(!(pg = (fPOINT3D *)malloc(5*sizeof(fPOINT3D)))) return;
+	for(i = 0; i < 6; i++) {
+		if(faces[i]) delete(faces[i]);
+		faces[i] = 0L;
+		}
+	if(flags & 0x800L) {		//height is data
+		tmp.fx = fPos.fx;			tmp.fy = height;
+		tmp.fz = fPos.fz;			o->fvec2ivec(&tmp, &fip2);
+		}
+	else {						//height is units
+		tmp.fx = tmp.fz = 0.0;		tmp.fy = height;
+		o->uvec2ivec(&tmp, &fip2);
+		fip2.fx += fip1.fx;			fip2.fy += fip1.fy;
+		fip2.fz += fip1.fz;
+		}
+	//calc output-device coordinates of cubic brick: 8 corners
+	tmp.fx = -(width/2.0);			tmp.fz = (depth/2.0);	tmp.fy = 0.0;
+	o->uvec2ivec(&tmp, &itmp);
+	cpt[0].fx= fip1.fx+itmp.fx;	cpt[0].fy= fip1.fy+itmp.fy;	cpt[0].fz= fip1.fz+itmp.fz;
+	cpt[2].fx= fip1.fx-itmp.fx;	cpt[2].fy= fip1.fy-itmp.fy;	cpt[2].fz= fip1.fz-itmp.fz;
+	cpt[4].fx= fip2.fx+itmp.fx;	cpt[4].fy= fip2.fy+itmp.fy;	cpt[4].fz= fip2.fz+itmp.fz;
+	cpt[6].fx= fip2.fx-itmp.fx;	cpt[6].fy= fip2.fy-itmp.fy;	cpt[6].fz= fip2.fz-itmp.fz;
+	tmp.fx = (width/2.0);			tmp.fz = (depth/2.0);	tmp.fy = 0.0;
+	o->uvec2ivec(&tmp, &itmp);
+	cpt[1].fx= fip1.fx+itmp.fx;	cpt[1].fy= fip1.fy+itmp.fy;	cpt[1].fz= fip1.fz+itmp.fz;
+	cpt[3].fx= fip1.fx-itmp.fx;	cpt[3].fy= fip1.fy-itmp.fy;	cpt[3].fz= fip1.fz-itmp.fz;
+	cpt[5].fx= fip2.fx+itmp.fx;	cpt[5].fy= fip2.fy+itmp.fy;	cpt[5].fz= fip2.fz+itmp.fz;
+	cpt[7].fx= fip2.fx-itmp.fx;	cpt[7].fy= fip2.fy-itmp.fy;	cpt[7].fz= fip2.fz-itmp.fz;
+	//set up 6 faces
+	pg[0].fx = pg[4].fx = cpt[0].fx;	pg[1].fx = cpt[1].fx;	
+	pg[2].fx = cpt[2].fx;				pg[3].fx = cpt[3].fx;
+	pg[0].fy = pg[4].fy = cpt[0].fy;	pg[1].fy = cpt[1].fy;	
+	pg[2].fy = cpt[2].fy;				pg[3].fy = cpt[3].fy;
+	pg[0].fz = pg[4].fz = cpt[0].fz;	pg[1].fz = cpt[1].fz;	
+	pg[2].fz = cpt[2].fz;				pg[3].fz = cpt[3].fz;
+	faces[0] = new plane(this, data, pg, 5, &Line, &Fill);
+	pg[2].fx = cpt[5].fx;				pg[3].fx = cpt[4].fx;
+	pg[2].fy = cpt[5].fy;				pg[3].fy = cpt[4].fy;
+	pg[2].fz = cpt[5].fz;				pg[3].fz = cpt[4].fz;
+	npl = new plane(this, data, pg, 5, &Line, &Fill);
+	if(npl->GetSize(SIZE_MAX_Z) > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
+	else {
+		faces[1] = faces[0];		faces[0] = npl;		
+		}
+	pg[0].fx = pg[4].fx = cpt[2].fx;	pg[1].fx = cpt[6].fx;	
+	pg[2].fx = cpt[5].fx;				pg[3].fx = cpt[1].fx;
+	pg[0].fy = pg[4].fy = cpt[2].fy;	pg[1].fy = cpt[6].fy;	
+	pg[2].fy = cpt[5].fy;				pg[3].fy = cpt[1].fy;
+	pg[0].fz = pg[4].fz = cpt[2].fz;	pg[1].fz = cpt[6].fz;	
+	pg[2].fz = cpt[5].fz;				pg[3].fz = cpt[1].fz;
+	npl = new plane(this, data, pg, 5, &Line, &Fill);
+	if((dtmp = npl->GetSize(SIZE_MAX_Z)) > faces[1]->GetSize(SIZE_MAX_Z)) faces[2] = npl;
+	else {
+		faces[2] = faces[1];
+		if(dtmp > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
+		else {
+			faces[1] = faces[0];	faces[0] = npl;
+			}
+		}
+	pg[2].fx = cpt[7].fx;				pg[3].fx = cpt[3].fx;
+	pg[2].fy = cpt[7].fy;				pg[3].fy = cpt[3].fy;
+	pg[2].fz = cpt[7].fz;				pg[3].fz = cpt[3].fz;
+	npl = new plane(this, data, pg, 5, &Line, &Fill);
+	dtmp = npl->GetSize(SIZE_MAX_Z);
+	for (i = 3; i; i--) {
+		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+			faces[i] = npl;			break;
+			}
+		else faces[i] = faces[i-1];
+		}
+	if(!i) faces[0] = npl;
+	pg[0].fx = pg[4].fx = cpt[4].fx;	pg[1].fx = cpt[7].fx;	
+	pg[2].fx = cpt[3].fx;				pg[3].fx = cpt[0].fx;
+	pg[0].fy = pg[4].fy = cpt[4].fy;	pg[1].fy = cpt[7].fy;	
+	pg[2].fy = cpt[3].fy;				pg[3].fy = cpt[0].fy;
+	pg[0].fz = pg[4].fz = cpt[4].fz;	pg[1].fz = cpt[7].fz;	
+	pg[2].fz = cpt[3].fz;				pg[3].fz = cpt[0].fz;
+	npl = new plane(this, data, pg, 5, &Line, &Fill);
+	dtmp = npl->GetSize(SIZE_MAX_Z);
+	for (i = 4; i; i--) {
+		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+			faces[i] = npl;			break;
+			}
+		else faces[i] = faces[i-1];
+		}
+	if(!i) faces[0] = npl;
+	pg[2].fx = cpt[6].fx;				pg[3].fx = cpt[5].fx;
+	pg[2].fy = cpt[6].fy;				pg[3].fy = cpt[5].fy;
+	pg[2].fz = cpt[6].fz;				pg[3].fz = cpt[5].fz;
+	npl = new plane(this, data, pg, 5, &Line, &Fill);
+	dtmp = npl->GetSize(SIZE_MAX_Z);
+	for (i = 5; i; i--) {
+		if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+			faces[i] = npl;			break;
+			}
+		else faces[i] = faces[i-1];
+		}
+	if(!i) faces[0] = npl;
+	rDims.left = rDims.right = (int)pg[0].fx;
+	rDims.top = rDims.bottom = (int)pg[0].fy;
+	for (i= 3; i < 6; i++) if(faces[i]) {
+		faces[i]->DoPlot(o);
+		UpdateMinMaxRect(&rDims, faces[i]->rDims.left, faces[i]->rDims.top);
+		UpdateMinMaxRect(&rDims, faces[i]->rDims.right, faces[i]->rDims.bottom);
+		}
+	free(pg);
+}
+
+void
+Brick::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+		mo = GetRectBitmap(&mrc, o);
+		if(faces) for(i = 3; i < 6; i++)
+			if(faces[i]) faces[i]->DoMark(o, mark);
+		o->UpdateRect(&rDims, false);
+		}
+	else if(mo)	RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Brick::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name) free(name);		name = 0L;
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;			depth *= ((scaleINFO*)tmpl)->sz.fy;
+		width *= ((scaleINFO*)tmpl)->sx.fy;		if(!(flags & 0x800L)) height *=  ((scaleINFO*)tmpl)->sx.fy;
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+		break;
+	case CMD_BAR_FILL:
+		if(tmpl) {
+			memcpy(&Fill, tmpl, sizeof(FillDEF));
+			Fill.hatch = 0L;
+			return true;
+			}
+		break;
+	case CMD_MRK_DIRTY:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_BRICK;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_REDRAW:
+		//Note: this command is issued either by Undo (no output given) or
+		//  by Plot3D::DoPlot after sorting all objects (output specified)
+		if(!parent) return false;
+		if(!o) return parent->Command(cmd, tmpl, o);
+		//Should we ever come here ?
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				if(faces && faces[3] && faces[4] && faces[5] &&
+					(faces[3]->ObjThere(mev->x, mev->y) || 
+					faces[4]->ObjThere(mev->x, mev->y) ||
+					faces[5]->ObjThere(mev->x, mev->y))){
+						o->ShowMark(CurrGO=this, MRK_GODRAW);
+						return true;
+						}
+				}
+			break;
+			}
+		break;
+	case CMD_UPDATE:
+		if(ssRef && cssRef > 5 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &depth);
+			data->GetValue(ssRef[4].y, ssRef[4].x, &width);
+			data->GetValue(ssRef[5].y, ssRef[5].x, &height);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+			if(flags & 0x800L) {		//height is data
+				((Plot*)parent)->CheckBounds3D(fPos.fx, height, fPos.fz);
+				}
+			return true;
+			}
+		break;
+	case CMD_SET_GO3D:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// line_segment: utility object to draw a piece of a polyline in 3D space
+line_segment::line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2)
+	:GraphObj(par, d)
+{
+	double tmp, tmp1, tmp2;
+
+	nli = 0;    nldata = 0L;	  ldata = 0L;	prop = 1.0;		df_go = 0L;
+	fmin.fx = fmax.fx = fmin.fy = fmax.fy = fmin.fz = fmax.fz = 0.0;
+	ndf_go = 0;
+	if(ld) memcpy(&Line, ld, sizeof(LineDEF));
+	if(p1 && p2 &&(ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
+		(ldata[0] = (POINT3D*)malloc(2 * sizeof(POINT3D))) &&
+		(nldata = (int*)calloc(1, sizeof(int)))){
+			if(Line.pattern) {
+				tmp1 = (tmp = (p2->x - p1->x)) * tmp;
+				tmp2 = (tmp1 += (tmp = (p2->y - p1->y)) * tmp);
+				tmp1 += (tmp = (p2->z - p1->z)) * tmp;
+				if(tmp1 > 1.0) prop = sqrt(tmp2)/sqrt(tmp1);
+				}
+			memcpy(&ldata[0][0], p1, sizeof(POINT3D));
+			memcpy(&ldata[0][1], p2, sizeof(POINT3D));
+			nldata[0] = 2;		nli = 1;
+			rDims.left = rDims.right = p1->x;	rDims.top = rDims.bottom = p1->y;
+			UpdateMinMaxRect(&rDims, p2->x, p2->y);
+			fmin.fx = (double)rDims.left;	fmin.fy = (double)rDims.top;
+			fmax.fx = (double)rDims.right;	fmax.fy = (double)rDims.bottom;
+			if(p2->z > p1->z) {
+				fmin.fz = (double)p1->z;	fmax.fz = (double)p2->z;
+				}
+			else {
+				fmin.fz = (double)p2->z;	fmax.fz = (double)p1->z;
+				}
+		}
+	Id = GO_LINESEG;
+}
+
+line_segment::~line_segment()
+{
+	int i;
+
+	if(ldata) {
+		for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
+		free(ldata);
+		}
+	if(nldata) free(nldata);		nldata = 0L;
+}
+
+double
+line_segment::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_MIN_Z:
+		return fmin.fz;
+	case SIZE_MAX_Z:
+		return fmax.fz;
+		}
+	return 0.0;
+}
+
+void
+line_segment::DoPlot(anyOutput *o)
+{
+	bDrawDone = false;		co = 0L;
+	if(df_go) free(df_go);
+	df_go = 0L;				ndf_go = 0;
+	if(o->VPscale > 1.5 && (
+		(rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+		(rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+		bDrawDone = true;		return;
+		}
+	if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+	Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+line_segment::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i, j;
+	POINT pts[2];
+	LineDEF cLine;
+	POINT3D *ap;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_DRAW_LATER:
+		if(!co) return false;
+		if(df_go){
+			for(i = 0; i < ndf_go; i++) if(df_go[i] == co) return true;
+			if(df_go = (GraphObj**)realloc(df_go, (ndf_go +1) * sizeof(GraphObj*))) {
+				df_go[ndf_go++] = co;
+				}
+			}
+		else {
+			if(df_go = (GraphObj**)malloc(sizeof(GraphObj*))){
+				df_go[0] = co;	ndf_go = 1;
+				}
+			}
+		return true;
+	case CMD_REDRAW:
+		if(bDrawDone) return false;
+		bDrawDone = true;
+		if(!nli) return false;
+		if(df_go) {
+			for(i = 0; i < ndf_go; i++) if(df_go[i]) df_go[i]->Command(cmd, tmpl, o);
+			free(df_go);	df_go = 0L;			ndf_go = 0L;
+			}
+		if(o && ldata && nldata){
+			memcpy(&cLine, &Line, sizeof(LineDEF));
+			cLine.patlength *= prop;
+			o->SetLine(&cLine);
+			for(i = 0; i < nli; i++) for(j = 0; j < (nldata[i]-1); j++) {
+				pts[0].x = ldata[i][j].x;	pts[0].y = ldata[i][j].y;
+				pts[1].x = ldata[i][j+1].x;	pts[1].y = ldata[i][j+1].y;
+				if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) o->oPolyline(pts, 2);
+				}
+			}
+		return true;
+	case CMD_CLIP:
+		if(co = (GraphObj*)tmpl){
+			switch(co->Id) {
+			case GO_PLANE:
+			case GO_SPHERE:
+				DoClip(co);
+				break;
+				}
+			}
+		return false;
+	case CMD_STARTLINE:
+		if(tmpl) {
+			if(ldata && nldata) {
+				ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
+				ldata[nli] = (POINT3D*)malloc(2 * sizeof(POINT3D));
+				nldata = (int*)realloc(nldata, sizeof(int)*(nli+1));
+				}
+			else {
+				ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
+				ldata[nli = 0] = (POINT3D*)malloc(2 * sizeof(POINT3D));
+				nldata = (int*)calloc(1, sizeof(int));
+				}
+			if(ldata && nldata) {
+				memcpy(&ldata[nli][0], tmpl, sizeof(POINT3D));
+				memcpy(&ldata[nli][1], tmpl, sizeof(POINT3D));
+				nldata[nli++] = 1;
+				return true;
+				}
+			}
+		break;
+	case CMD_ADDTOLINE:
+		if((ap = (POINT3D*)tmpl) && ldata && nldata && nli && nldata[i =(nli-1)]) {
+			j = nldata[i];
+			ldata[i] = (POINT3D*)realloc(ldata[i], (nldata[i]+2) * sizeof(POINT3D));
+			if(j && ldata[i][j-1].x == ap->x && ldata[i][j-1].y == ap->y &&
+				ldata[i][j-1].z == ap->z) return true;
+			else {
+				j = (nldata[i]++);
+				}
+			memcpy(&ldata[i][j-1], tmpl, sizeof(POINT3D));
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+void *
+line_segment::ObjThere(int x, int y)
+{
+	int i, j;
+	POINT pts[2];
+
+	if(ldata && nldata){
+		for(i = 0; i < nli; i++) for(j = 0; j < nldata[i]; j +=2) {
+			pts[0].x = ldata[i][j].x;	pts[0].y = ldata[i][j].y;
+			pts[1].x = ldata[i][j+1].x;	pts[1].y = ldata[i][j+1].y;
+			if(IsCloseToLine(&pts[0], &pts[1], x, y))return this;
+			}
+		}
+	return 0L;
+}
+
+void
+line_segment::DoClip(GraphObj *co)
+{
+	RECT cliprc;
+	int o_nli, *o_nldata = 0L;
+	POINT3D **o_ldata = 0L, *pts = 0L, *pla;
+	int i, j, k, np, r, cx, cy, cz;
+	bool is_valid = false;
+
+	cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+	cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+	cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+	cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+	if(OverlapRect(&rDims, &cliprc)) {
+		if(!(pts = (POINT3D*)calloc(2, sizeof(POINT3D))))return;
+		o_nli = nli;		nli = 0;
+		o_nldata = nldata;	nldata = 0L;
+		o_ldata = ldata;	ldata = 0L;
+		switch(co->Id) {
+		case GO_SPHERE:
+			cx = iround(co->GetSize(SIZE_XPOS));
+			cy = iround(co->GetSize(SIZE_YPOS));
+			cz = iround(co->GetSize(SIZE_ZPOS));
+			r = iround(co->GetSize(SIZE_RADIUS1));
+			for(i = 0; i < o_nli; i++) for(j = 0; j < (o_nldata[i]-1); j ++) {
+				pts[0].x = o_ldata[i][j].x;			pts[0].y = o_ldata[i][j].y;
+				pts[0].z = o_ldata[i][j].z;			pts[1].x = o_ldata[i][j+1].x;
+				pts[1].y = o_ldata[i][j+1].y;		pts[1].z = o_ldata[i][j+1].z;
+				clip_line_sphere(this, &pts, r, cx, cy, cz);
+				}
+			break;
+		case GO_PLANE:
+			for(i = 0; ((plane*)co)->GetPolygon(&pla, &np, i); i++){
+				for(j = 0; j < o_nli; j++) {
+					if(o_nldata[j] >1) for(k = 0; k < (o_nldata[j]-1); k++){
+						pts[0].x = o_ldata[j][k].x;			pts[0].y = o_ldata[j][k].y;
+						pts[0].z = o_ldata[j][k].z;			pts[1].x = o_ldata[j][k+1].x;
+						pts[1].y = o_ldata[j][k+1].y;		pts[1].z = o_ldata[j][k+1].z;
+						if(pts[0].x != pts[1].x || pts[0].y != pts[1].y || pts[0].z != pts[1].z)
+							clip_line_plane(this, &pts, pla, np, ((plane*)co)->GetVec());
+						}
+					}
+				if(nli) is_valid = true;
+				if(o_ldata) {
+					for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
+					free(o_ldata);
+					}
+				if(o_nldata) free(o_nldata);
+				o_nli = nli;		nli = 0;
+				o_nldata = nldata;	nldata = 0L;
+				o_ldata = ldata;	ldata = 0L;
+				if(!o_nli) return;				//line is completly hidden
+				}
+			if(is_valid || i==0){
+				nli = o_nli;		o_nli = 0;
+				nldata = o_nldata;	o_nldata = 0L;
+				ldata = o_ldata;	o_ldata = 0L;
+				}
+			break;
+		default:
+			nli = o_nli;		o_nli = 0;
+			nldata = o_nldata;	o_nldata = 0L;
+			ldata = o_ldata;	o_ldata = 0L;
+			break;
+			}
+		if(pts) free(pts);
+		}
+	if(o_ldata) {
+		for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
+		free(o_ldata);
+		}
+	if(o_nldata) free(o_nldata);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define a drop line in 3D space
+DropLine3D::DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc,
+		int xr, int yc, int yr, int zc, int zr):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	Id = GO_DROPL3D;
+	memcpy(&fPos, p1, sizeof(fPOINT3D));
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = zc;	ssRef[2].y = zr;
+			cssRef = 3;
+			}
+		}
+	bModified = false;
+	type = 0x01;
+}
+
+DropLine3D::DropLine3D(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+DropLine3D::~DropLine3D()
+{
+	if(bModified) Undo.InvalidGO(this);
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+void
+DropLine3D::DoPlot(anyOutput *o)
+{
+	fPOINT3D fip, fp, fp1;
+	POINT3D p1, p2;
+	int i;
+
+	if(!parent || !o || !o->fvec2ivec(&fPos, &fip)) return;
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	for(i = 0; i < 6; i++){
+		if(ls[i]) delete(ls[i]);
+		ls[i] = 0L;
+		}
+	p1.x = iround(fip.fx);	p1.y = iround(fip.fy);	p1.z = iround(fip.fz);
+	rDims.left = rDims.right = p1.x;	rDims.top = rDims.bottom = p1.y;
+	for(i = 0; i < 6; i++) {
+		fp.fx = fPos.fx;	fp.fy = fPos.fy;	fp.fz = fPos.fz;
+		if(type & (1 << i)){
+			switch (i) {
+			case 0:	fp.fy = parent->GetSize(SIZE_BOUNDS_YMIN);	break;
+			case 1:	fp.fy = parent->GetSize(SIZE_BOUNDS_YMAX);	break;
+			case 2:	fp.fz = parent->GetSize(SIZE_BOUNDS_ZMIN);	break;
+			case 3:	fp.fz = parent->GetSize(SIZE_BOUNDS_ZMAX);	break;
+			case 4:	fp.fx = parent->GetSize(SIZE_BOUNDS_XMIN);	break;
+			case 5:	fp.fx = parent->GetSize(SIZE_BOUNDS_XMAX);	break;
+				}
+			o->fvec2ivec(&fp, &fp1);		p2.x = iround(fp1.fx);
+			p2.y = iround(fp1.fy);			p2.z = iround(fp1.fz);
+			UpdateMinMaxRect(&rDims, p2.x, p2.y);
+			if(ls[i] = new line_segment(this, data, &Line, &p1, &p2)) ls[i]->DoPlot(o);
+			mpts[i][0].x = p1.x;	mpts[i][0].y = p1.y;
+			mpts[i][1].x = p2.x;	mpts[i][1].y = p2.y;
+			}
+		}
+	IncrementMinMaxRect(&rDims, 5);
+}
+
+void
+DropLine3D::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+
+	if(mark) {
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+		mo = GetRectBitmap(&mrc, o);
+		for(i = 0; i < 6; i++) {
+			if(type & (1 << i)){
+				InvertLine(mpts[i], 2, &Line, 0L, o, mark);
+				}
+			}
+		o->UpdateRect(&mrc, false);
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+DropLine3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	int i;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		for(i = 0; i < 6; i++){
+			if(ls[i]) delete(ls[i]);
+			ls[i] = 0L;
+			}
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name) free(name);		name = 0L;
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_DL_TYPE:
+		if(tmpl && *((int*)tmpl)) type = *((int*)tmpl);
+		return true;
+	case CMD_DL_LINE:
+		if(tmpl) memcpy(&Line, tmpl, sizeof(LineDEF));
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_DROPL3D;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_REDRAW:
+		//Note: this command is issued either by Undo (no output given) or
+		//  by Plot3D::DoPlot after sorting all objects (output specified)
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				for(i = 0; i < 6; i++) {
+					if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
+						o->ShowMark(this, MRK_GODRAW);
+						return true;
+						}
+					}
+				}
+			break;
+			}
+		break;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >2 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+			return true;
+			}
+		break;
+	case CMD_SET_GO3D:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define an arrow in 3D space
+Arrow3D::Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1,
+		int xr1, int yc1, int yr1, int zc1, int zr1, int xc2, int xr2, int yc2, 
+		int yr2, int zc2, int zr2):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	Id = GO_ARROW3D;
+	memcpy(&fPos1, p1, sizeof(fPOINT3D));	memcpy(&fPos2, p2, sizeof(fPOINT3D));
+	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || zc1 >= 0 || zr1 >= 0 || 
+		xc2 >= 0 || xr2 >= 0 || yc2 >= 0 || yr2 >= 0 || zc2 >= 0 || zr2 >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
+			ssRef[0].x = xc1;	ssRef[0].y = xr1;
+			ssRef[1].x = yc1;	ssRef[1].y = yr1;
+			ssRef[2].x = zc1;	ssRef[2].y = zr1;
+			ssRef[3].x = xc2;	ssRef[3].y = xr2;
+			ssRef[4].x = yc2;	ssRef[4].y = yr2;
+			ssRef[5].x = zc2;	ssRef[5].y = zr2;
+			cssRef = 6;
+			}
+		}
+	bModified = false;
+}
+
+Arrow3D::Arrow3D(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+Arrow3D::~Arrow3D()
+{
+	if(bModified) Undo.InvalidGO(this);
+	Command(CMD_FLUSH, 0L, 0L);
+}
+
+bool
+Arrow3D::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_ARROW_LINE:
+		Line.width = value;
+		return true;
+	case SIZE_ARROW_CAPWIDTH:
+		cw = value;
+		return true;
+	case SIZE_ARROW_CAPLENGTH:
+		cl = value;
+		return true;
+		}
+	return false;
+}
+
+bool
+Arrow3D::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_ARROW:
+		Line.color = col;
+		return true;
+		}
+	return false;
+}
+
+void
+Arrow3D::DoPlot(anyOutput *o)
+{
+	double si, csi, tmp, cwr, clr, d, d1, d2;
+	fPOINT3D fip1, fip2, tria[3];
+	POINT3D p1, p2, cp1, cp2;
+	FillDEF fill;
+	int i;
+
+	if(!parent || !o || !o->fvec2ivec(&fPos1, &fip1) ||!o->fvec2ivec(&fPos2, &fip2)) return;
+	for(i = 0; i < 3; i++){
+		if(ls[i]) delete(ls[i]);
+		ls[i] = 0L;
+		}
+	p1.x = iround(fip1.fx);	p1.y = iround(fip1.fy);	p1.z = iround(fip1.fz);
+	p2.x = iround(fip2.fx);	p2.y = iround(fip2.fy);	p2.z = iround(fip2.fz);
+	if(p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) return;	//zero length arrow
+	rDims.left = rDims.right = p1.x;	rDims.top = rDims.bottom = p1.y;
+	UpdateMinMaxRect(&rDims, p2.x, p2.y);
+	IncrementMinMaxRect(&rDims, 5);
+	if(ls[0] = new line_segment(this, data, &Line, &p1, &p2)) ls[0]->DoPlot(o);
+	mpts[0][0].x = p1.x;	mpts[0][0].y = p1.y;	mpts[0][1].x = p2.x;	mpts[0][1].y = p2.y;
+	if(p1.x == p2.x && p1.y == p2.y) return;			//zero length in 2D
+	if((type & 0xff) == ARROW_NOCAP) return;			//no cap;
+	//calculate sine and cosine for cap
+	si = fip1.fy-fip2.fy;
+	tmp = fip2.fx - fip1.fx;
+	si = si/sqrt(si*si + tmp*tmp);
+	csi = fip2.fx-fip1.fx;
+	tmp = fip2.fy - fip1.fy;
+	csi = csi/sqrt(csi*csi + tmp*tmp);
+	//cap corners
+	d1 = (d = fip2.fx - fip1.fx) * d;
+	d1 += ((d = fip2.fy - fip1.fy) * d);
+	d2 = d1 + ((d = fip2.fz - fip1.fz) * d);
+	d1 = sqrt(d1);	d2 = sqrt(d2);	d = d1/d2;
+	cwr = cw;	clr = cl*d;
+	cp1.x = p2.x - o->un2ix(csi*clr + si*cwr/2.0);
+	cp1.y = p2.y + o->un2iy(si*clr - csi*cwr/2.0);
+	cp2.x = p2.x - o->un2ix(csi*clr - si*cwr/2.0);
+	cp2.y = p2.y + o->un2iy(si*clr + csi*cwr/2.0);
+	cp1.z = cp2.z = p2.z;
+	mpts[1][0].x = p2.x;	mpts[1][0].y = p2.y;	mpts[1][1].x = cp1.x;	mpts[1][1].y = cp1.y;
+	mpts[2][0].x = p2.x;	mpts[2][0].y = p2.y;	mpts[2][1].x = cp2.x;	mpts[2][1].y = cp2.y;
+	if((type & 0xff) == ARROW_LINE) {
+		if(ls[1] = new line_segment(this, data, &Line, &p2, &cp1)) ls[1]->DoPlot(o);
+		if(ls[2] = new line_segment(this, data, &Line, &p2, &cp2)) ls[2]->DoPlot(o);
+		}
+	else if((type & 0xff) == ARROW_TRIANGLE) {
+		fill.type = FILL_NONE;	fill.color = Line.color;
+		fill.scale = 1.0;		fill.hatch = 0L;
+		tria[0].fz = tria[1].fz = tria[2].fz = fip2.fz;
+		tria[0].fx = cp1.x;		tria[0].fy = cp1.y;
+		tria[1].fx = fip2.fx;	tria[1].fy = fip2.fy;
+		tria[2].fx = cp2.x;		tria[2].fy = cp2.y;
+		if(cap = new plane(this, data, tria, 3, &Line, &fill))cap->DoPlot(o);
+	}
+}
+
+void
+Arrow3D::DoMark(anyOutput *o, bool mark)
+{
+	int i;
+
+	if(mark) {
+		for(i = 0; i < 3; i++) {
+			if(ls[i]){
+				InvertLine(mpts[i], 2, &Line, 0L, o, mark);
+				}
+			}
+		}
+	else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Arrow3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	int i;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		for(i = 0; i < 3; i++){
+			if(ls[i]) delete(ls[i]);
+			ls[i] = 0L;
+			}
+		if(cap) delete(cap);	cap = 0L;
+		if(ssRef) free(ssRef);		ssRef = 0L;
+		if(name) free(name);		name = 0L;
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		 cw *= ((scaleINFO*)tmpl)->sy.fy;					cl *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_ARROW3D;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_MRK_DIRTY:			//from Undo ?
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+				for(i = 0; i < 3; i++) {
+					if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
+						o->ShowMark(this, MRK_GODRAW);
+						return true;
+						}
+					}
+				}
+			break;
+			}
+		break;
+	case CMD_ARROW_ORG3D:
+		if(tmpl) memcpy(&fPos1, tmpl, sizeof(fPOINT3D));
+		return true;
+	case CMD_ARROW_TYPE:
+		if(tmpl) type = *((int*)tmpl);
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >5 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos2.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos2.fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &fPos2.fz);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &fPos1.fx);
+			data->GetValue(ssRef[4].y, ssRef[4].x, &fPos1.fy);
+			data->GetValue(ssRef[5].y, ssRef[5].x, &fPos1.fz);
+			return true;
+			}
+		return false;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+			((Plot*)parent)->CheckBounds3D(fPos1.fx, fPos1.fy, fPos1.fz);
+			((Plot*)parent)->CheckBounds3D(fPos2.fx, fPos2.fy, fPos2.fz);
+			return true;
+			}
+		break;
+	case CMD_SET_GO3D:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a data line in 3D space
+Line3D::Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz)
+	:GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	if(rx && rx[0]) x_range = (char*)memdup(rx, (int)strlen(rx)+2, 0L);
+	if(ry && ry[0]) y_range = (char*)memdup(ry, (int)strlen(ry)+2, 0L);
+	if(rz && rz[0]) z_range = (char*)memdup(rz, (int)strlen(rz)+2, 0L);
+	DoUpdate();
+	Id = GO_LINE3D;
+	bModified = false;
+}
+
+Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, int xc1, int xr1, int yc1, int yr1,
+		int zc1, int zr1, int xc2, int xr2, int yc2, int yr2, int zc2, int zr2)
+	:GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	if(pt && n_pt) {
+		values = (fPOINT3D*)memdup(pt, n_pt * sizeof(fPOINT3D), 0L);
+		nPts = n_pt;
+		ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
+		}
+	if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || zc1 >= 0 || zr1 >= 0 || 
+		xc2 >= 0 || xr2 >= 0 || yc2 >= 0 || yr2 >= 0 || zc2 >= 0 || zr2 >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
+			ssRef[0].x = xc1;	ssRef[0].y = xr1;
+			ssRef[1].x = yc1;	ssRef[1].y = yr1;
+			ssRef[2].x = zc1;	ssRef[2].y = zr1;
+			ssRef[3].x = xc2;	ssRef[3].y = xr2;
+			ssRef[4].x = yc2;	ssRef[4].y = yr2;
+			ssRef[5].x = zc2;	ssRef[5].y = zr2;
+			cssRef = 6;
+			}
+		}
+	Id = GO_LINE3D;
+	bModified = false;
+}
+
+Line3D::Line3D(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+Line3D::~Line3D()
+{
+	int i;
+
+	if(bModified) Undo.InvalidGO(this);
+	if(ls){
+		for(i = 0; i < (nPts-1); i++) if(ls[i]) delete(ls[i]);
+		free(ls);
+		}
+	if(pts && npts) free(pts);		pts = 0L;		npts = 0;	cssRef = 0;
+	if(x_range) free(x_range);		x_range = 0L;
+	if(y_range) free(y_range);		y_range = 0L;
+	if(z_range) free(z_range);		z_range = 0L;
+	if(values) free(values);		values = 0L;
+	if(ssRef) free(ssRef);			ssRef = 0L;
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+}
+
+void
+Line3D::DoPlot(anyOutput *o)
+{
+	int i, j;
+	fPOINT3D fip;
+	POINT3D p1, p2;
+	POINT np;
+
+
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+	if(ls) {
+		if(pts && npts) free(pts);
+		npts = 0;	if(!(pts = (POINT*)calloc(nPts, sizeof(POINT))))return;
+		for(i = 0; i< nPts; i++) {
+			if(!o->fvec2ivec(&values[i], &fip)) return;
+			p2.x = iround(fip.fx);	p2.y = iround(fip.fy);	p2.z = iround(fip.fz);
+			np.x = p2.x;			np.y = p2.y;
+			AddToPolygon(&npts, pts, &np);
+			if(i) {
+				UpdateMinMaxRect(&rDims, np.x, np.y);
+				j = i-1;
+				if(ls[j]) delete(ls[j]);
+				if(ls[j] = new line_segment(this, data, &Line, &p1, &p2)) {
+					ls[j]->DoPlot(o);
+					}
+				}
+			else {
+				rDims.left = rDims.right = p2.x;
+				rDims.top = rDims.bottom = p2.y;
+				}
+			p1.x = p2.x;	p1.y = p2.y;	p1.z = p2.z;
+			}
+		IncrementMinMaxRect(&rDims, 6);
+		}
+}
+
+void
+Line3D::DoMark(anyOutput *o, bool mark)
+{
+	if(mark) {
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+		mo = GetRectBitmap(&mrc, o);
+		InvertLine(pts, npts, &Line, &rDims, o, true);
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Line3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	POINT p1;
+	int i;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(name) free(name);		name = 0L;
+		return true;
+	case CMD_SCALE:
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_SET_LINE:
+		if(tmpl) {
+			memcpy(&Line, tmpl, sizeof(LineDEF));
+			return true;
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_LINE3D;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_REDRAW:
+		//Note: this command is issued  by Undo (no output given)
+		if(!parent) return false;
+		if(!o) return parent->Command(cmd, tmpl, o);
+		//Should we ever come here ?
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!IsInRect(&rDims, p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPts <2 ||
+				!IsCloseToPL(p1, pts, npts))return false;
+			o->ShowMark(CurrGO=this, MRK_GODRAW);
+			return true;
+			}
+		return false;
+	case CMD_UPDATE:
+		if(parent && parent->Id != GO_GRID3D) {
+			Undo.DataMem(this, (void**)&values, nPts * sizeof(fPOINT3D), &nPts, UNDO_CONTINUE);
+			}
+		if(ssRef && cssRef >5 && data && nPts == 2) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &values[0].fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &values[0].fy);
+			data->GetValue(ssRef[2].y, ssRef[2].x, &values[0].fz);
+			data->GetValue(ssRef[3].y, ssRef[3].x, &values[1].fx);
+			data->GetValue(ssRef[4].y, ssRef[4].x, &values[1].fy);
+			data->GetValue(ssRef[5].y, ssRef[5].x, &values[1].fz);
+			return true;
+			}
+		else DoUpdate();
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH){
+			if(min.fx == max.fx || min.fy == max.fy){	//z's may be equal !
+				min.fx = min.fy = min.fz = HUGE_VAL;
+				max.fx = max.fy = max.fz = -HUGE_VAL;
+				for(i = 0; i < nPts; i++) {
+					if(values[i].fx < min.fx) min.fx = values[i].fx;
+					if(values[i].fy < min.fy) min.fy = values[i].fy;
+					if(values[i].fz < min.fz) min.fz = values[i].fz;
+					if(values[i].fx > max.fx) max.fx = values[i].fx;
+					if(values[i].fy > max.fy) max.fy = values[i].fy;
+					if(values[i].fz > max.fz) max.fz = values[i].fz;
+					}
+				}
+			((Plot*)parent)->CheckBounds3D(min.fx, min.fy, min.fz);
+			((Plot*)parent)->CheckBounds3D(max.fx, max.fy, max.fz);
+			return true;
+			}
+		return false;
+	case CMD_SET_GO3D:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+		}
+	return false;
+}
+
+void
+Line3D::DoUpdate()
+{
+	int n1 = 0, ic = 0, i, j, k, l, m, n;
+	double x, y, z;
+	AccRange *rX=0L, *rY=0L, *rZ=0L;
+
+	if(!x_range || !y_range || !z_range) return;
+	if(values) free(values);	values = 0L;
+	if(ls) free(ls);			ls = 0L;
+	rX = new AccRange(x_range);
+	rY = new AccRange(y_range);
+	rZ = new AccRange(z_range);
+	min.fx = min.fy = min.fz = HUGE_VAL;	max.fx = max.fy = max.fz = -HUGE_VAL;
+	if(rX) n1 = rX->CountItems();
+	if(n1 && rY && rZ && (values = (fPOINT3D*)malloc(n1 * sizeof(fPOINT3D)))){
+		rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
+		rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
+		rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
+		do {
+			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && 
+				data->GetValue(n, m, &z)){
+				values[ic].fx = x;	values[ic].fy = y;	values[ic].fz = z;
+				if(x < min.fx) min.fx = x;	if(x > max.fx) max.fx = x;
+				if(y < min.fy) min.fy = y;	if(y > max.fy) max.fy = y;
+				if(z < min.fz) min.fz = z;	if(z > max.fz) max.fz = z;
+				ic++;
+				}
+			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+		nPts = ic;
+		if(ic > 1) ls = (line_segment **)calloc(ic-1, sizeof(line_segment*));
+		}
+	if(rX) delete(rX);	if(rY) delete(rY); if(rZ) delete(rZ);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the text label class 
+Label::Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
+	 int xc, int xr, int yc, int yr, int tc, int tr):GraphObj(par, d)
+{
+	int cb;
+
+	FileIO(INIT_VARS);
+	fPos.fx = x;		fPos.fy = y;		flags = flg;
+	if(parent){
+		fDist.fx = parent->GetSize(SIZE_LB_XDIST);
+		fDist.fy = parent->GetSize(SIZE_LB_YDIST);
+		}
+	Id = GO_LABEL;
+	if(td){
+		memcpy(&TextDef, td, sizeof(TextDEF));
+		if(td->text && td->text[0]) {
+			cb = (int)strlen(td->text)+1;			if(cb < 20) cb = 20;
+			TextDef.text = (char*)malloc(cb *sizeof(char));
+			rlp_strcpy(TextDef.text, cb, td->text);
+			}
+		}
+	if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || tc >= 0 || tr >= 0) {
+		if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+			ssRef[0].x = xc;	ssRef[0].y = xr;
+			ssRef[1].x = yc;	ssRef[1].y = yr;
+			ssRef[2].x = tc;	ssRef[2].y = tr;
+			cssRef = 3;
+			}
+		}
+}
+
+Label::Label(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+Label::~Label()
+{
+	HideTextCursor();
+	Command(CMD_FLUSH, 0L, 0L);
+	if(fmt_txt) delete(fmt_txt);			fmt_txt = 0L;
+	if(bModified)Undo.InvalidGO(this);
+}
+
+double
+Label::GetSize(int select)
+{
+	switch(select){
+	case SIZE_CURSORPOS:
+		return (double)CursorPos;
+	case SIZE_CURSOR_XMIN:
+		return (double) (Cursor.right > Cursor.left ? Cursor.left : Cursor.right);
+	case SIZE_CURSOR_XMAX:
+		return (double) (Cursor.right > Cursor.left ? Cursor.right : Cursor.left);
+	case SIZE_CURSOR_YMIN:
+		return (double) (Cursor.bottom > Cursor.top ? Cursor.top : Cursor.bottom);
+	case SIZE_CURSOR_YMAX:
+		return (double) (Cursor.bottom > Cursor.top ? Cursor.bottom : Cursor.top);
+	case SIZE_MIN_Z:	case SIZE_MAX_Z:	case SIZE_ZPOS:
+		return curr_z;
+		}
+	return 0.0;
+}
+
+bool
+Label::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_LB_XDIST:			fDist.fx = value;		return true;
+	case SIZE_LB_YDIST:			fDist.fy = value;		return true;
+	case SIZE_XPOS:				fPos.fx = value;		return true;
+	case SIZE_YPOS:				fPos.fy = value;		return true;
+	case SIZE_ZPOS:				curr_z = value;			return is3D = true;
+		}
+	return false;
+}
+
+bool
+Label::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff) {
+	case COL_TEXT:
+		if(select & UNDO_STORESET) {
+			Undo.ValDword(this, &TextDef.ColTxt, UNDO_CONTINUE);
+			bModified = true;
+			}
+		TextDef.ColTxt = col;			bBGvalid = false;
+		return true;
+	case COL_BG:
+		bgcolor = col;	bBGvalid = true;
+		return true;
+		}
+	return false;
+}
+
+void
+Label::DoPlot(anyOutput *o)
+{
+	if(is3D && parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+	DoPlotText(o);
+}
+
+void
+Label::DoMark(anyOutput *o, bool mark)
+{
+	DWORD bgpix[16];
+	int i, d, d1, ix, iy, dx, dy, n;
 	RECT mrc;
-	anyOutput *mo;
-
-	if(mark) {
+	anyOutput *mo;
+
+	if(mark) {
 		//find color with maximum contrast to text
 		if(!bBGvalid) {
 			mrc.left = rDims.left;		mrc.right = rDims.right;
@@ -5126,1198 +5250,2013 @@ Label::DoMark(anyOutput *o, bool mark)
 						i++;
 						}
 					}
-				DelBitmapClass(mo);		n = i;
-				}
-			bgcolor = bgpix[0];
-			d = ColDiff(bgcolor, TextDef.ColTxt);
-			for(i = 1; i < n; i++) {
-				if(d < (d1 = ColDiff(bgpix[i], TextDef.ColTxt))) {
-					d = d1;		bgcolor = bgpix[i];
-					}
-				}
-			if(!d) bgcolor = TextDef.ColTxt ^ 0x00ffffffL;
-			bBGvalid = true;
-			}
-		//in dialogs parent has no parent
-		if(parent && parent->parent) o->ShowLine(pts, 5, TextDef.ColTxt);
-		ShowCursor(o);	CurrGO = this;		CurrLabel = this;
-		}
-	else {
-		HideTextCursor();
-		bgLine.color = bgcolor;			o->SetLine(&bgLine);
-		//in dialogs parent has no parent
-		if(parent && parent->parent) o->oPolyline(pts, 5);
-		IncrementMinMaxRect(&rDims, 3);
-		o->UpdateRect(&rDims, false);	IncrementMinMaxRect(&rDims, -3);
-		if(CurrLabel == this) CurrLabel = 0L;
-		if(parent && parent->Id != GO_MLABEL && (!TextDef.text || !TextDef.text[0]))
-			parent->Command(CMD_DELOBJ, (void*)this, o);
-		}
-}
-
-bool
-Label::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	char *tmptxt;
-
-	if(cmd != CMD_SET_DATAOBJ && !parent) return false;
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(CurrLabel == this) CurrLabel = 0L;
-		if(TextDef.text) free(TextDef.text);	TextDef.text = 0L;
-		if(ssRef) free(ssRef);					ssRef = 0L;
-		return true;
-	case CMD_POS_FIRST:		case CMD_POS_LAST:
-		Undo.ValInt(this, &CursorPos, 0L);
-		bModified = true;
-		if(o && TextDef.text) {
-			CursorPos = (cmd == CMD_POS_LAST) ? strlen(TextDef.text) : 0;
-			ShowCursor(o);
-			return true;
-			}
-		return false;
-	case CMD_CURRLEFT:
-		if(o && CursorPos >0 && TextDef.text && fmt_txt) {
-			Undo.ValInt(this, &CursorPos, 0L);
-			bModified = true;		fmt_txt->cur_left(&CursorPos);			ShowCursor(o);
-			return true;
-			}
-		return false;
-	case CMD_CURRIGHT:
-		if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text) && fmt_txt) {
-			Undo.ValInt(this, &CursorPos, 0L);
-			bModified = true;		fmt_txt->cur_right(&CursorPos);			ShowCursor(o);
-			return true;
-			}
-		return false;
-	case CMD_ADDCHAR:
-		SetModified();
-		if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
-		//value 8 == backspace
-	case CMD_BACKSP:
-		SetModified();
-		if(CursorPos <=0 && o) {
-			if(parent->Id == GO_MLABEL) {
-				parent->Command(CMD_SETFOCUS, this, o);
-				return parent->Command(CMD_BACKSP, tmpl, o);
-				}
-			RedrawEdit(o);
-			return true;
-			}
-		Undo.ValInt(this, &CursorPos, 0L);
-		CursorPos--;							//continue as if delete
-	case CMD_DELETE:
-		SetModified();
-		if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, 0L);
-		if(TextDef.text && TextDef.text[CursorPos]) {
-			Undo.String(this, &TextDef.text, UNDO_CONTINUE);
-			strcpy(TextDef.text + CursorPos, TextDef.text + CursorPos + 1);
-			if(o)RedrawEdit(o);
-			}
-		else if(TextDef.text && parent->Id == GO_MLABEL) {
-			parent->Command(CMD_SETFOCUS, this, o);
-			return parent->Command(CMD_DELETE, tmpl, o);
-			}
-		else o->HideMark();
-		break;
-	case CMD_GETTEXT:
-		if(TextDef.text && tmpl) {
-			strcpy((char*)tmpl, TextDef.text);
-			return true;
-			}
-		return false;
-	case CMD_SETTEXT:
-		if(TextDef.text) free(TextDef.text);
-		if(tmpl) TextDef.text = strdup((char*)tmpl);
-		else TextDef.text = 0L;
-		return true;
-	case CMD_GETTEXTDEF:
-		if(!tmpl) return false;
-		memcpy(tmpl, &TextDef, sizeof(TextDEF));
-		return true;
-	case CMD_SETTEXTDEF:
-		if(!tmpl)return false;
-		tmptxt = TextDef.text;
-		memcpy(&TextDef, tmpl, sizeof(TextDEF));
-		if(!TextDef.text){
-			TextDef.text = tmptxt;
-			tmptxt = 0L;
-			}
-		else if(((TextDEF*)tmpl)->text) TextDef.text = strdup(((TextDEF*)tmpl)->text);
-		if(tmptxt) free(tmptxt);
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_LABEL;
-		data = (DataObj*)tmpl;
-		return true;
-	case CMD_UPDATE:
-		if(ssRef && cssRef >2 && data) {
-			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
-			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
-			if(data->GetText(ssRef[2].y, ssRef[2].x, TmpTxt, TMP_TXT_SIZE)) {
-				Undo.String(this, &TextDef.text, UNDO_CONTINUE);
-				TextDef.text = (char*)realloc(TextDef.text, strlen(TmpTxt)+2);
-				if(TmpTxt[0]) strcpy(TextDef.text, TmpTxt);
-				else TextDef.text[0] = 0;
-				}
-			return true;
-			}
-		return false;
-	case CMD_SELECT:
-		if(!o || !tmpl) return false;
-		CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
-		o->ShowMark(this, MRK_GODRAW);
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(ObjThere(mev->x, mev->y)) {
-				if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
-				CalcCursorPos(mev->x, mev->y, o);
-				o->ShowMark(this, MRK_GODRAW);
-				return true;
-				}
-			break;
-			}
-		break;
-	case CMD_AUTOSCALE:
-		if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
-			&& (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
-			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-			return true;
-			}
-		break;
+				DelBitmapClass(mo);		n = i;
+				}
+			bgcolor = bgpix[0];
+			d = ColDiff(bgcolor, TextDef.ColTxt);
+			for(i = 1; i < n; i++) {
+				if(d < (d1 = ColDiff(bgpix[i], TextDef.ColTxt))) {
+					d = d1;		bgcolor = bgpix[i];
+					}
+				}
+			if(!d) bgcolor = TextDef.ColTxt ^ 0x00ffffffL;
+			bBGvalid = true;
+			}
+		//in dialogs parent has no parent
+		if(parent && parent->parent) o->ShowLine(pts, 5, TextDef.ColTxt);
+		ShowCursor(o);	CurrGO = this;		CurrLabel = this;
+		}
+	else {
+		HideTextCursor();
+		bgLine.color = bgcolor;			o->SetLine(&bgLine);
+		//in dialogs parent has no parent
+		if(parent && parent->parent) o->oPolyline(pts, 5);
+		IncrementMinMaxRect(&rDims, 3);
+		o->UpdateRect(&rDims, false);	IncrementMinMaxRect(&rDims, -3);
+		if(CurrLabel == this) CurrLabel = 0L;
+		if(parent && parent->Id != GO_MLABEL && (!TextDef.text || !TextDef.text[0]))
+			parent->Command(CMD_DELOBJ, (void*)this, o);
+		}
+}
+
+bool
+Label::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	scaleINFO *scale;
+	int cb;
+
+	if(cmd != CMD_SET_DATAOBJ && !parent) return false;
+	switch (cmd) {
+	case CMD_SCALE:
+		scale = (scaleINFO*)tmpl;
+		if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
+		if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
+		fDist.fx *= scale->sx.fy;				fDist.fy *= scale->sy.fy;
+		TextDef.fSize *= scale->sx.fy;			TextDef.iSize = 0;
+		return true;
+	case CMD_FLUSH:
+		if(CurrLabel == this) CurrLabel = 0L;
+		if(TextDef.text) free(TextDef.text);	TextDef.text = 0L;
+		if(ssRef) free(ssRef);					ssRef = 0L;
+		return true;
+	case CMD_POS_FIRST:		case CMD_POS_LAST:
+		Undo.ValInt(this, &CursorPos, 0L);
+		bModified = true;
+		if(o && TextDef.text) {
+			CursorPos = (cmd == CMD_POS_LAST) ? (int)strlen(TextDef.text) : 0;
+			ShowCursor(o);
+			return true;
+			}
+		return false;
+	case CMD_CURRLEFT:
+		if(o && CursorPos >0 && TextDef.text && fmt_txt) {
+			Undo.ValInt(this, &CursorPos, 0L);
+			bModified = true;		fmt_txt->cur_left(&CursorPos);			ShowCursor(o);
+			return true;
+			}
+		return false;
+	case CMD_CURRIGHT:
+		if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text) && fmt_txt) {
+			Undo.ValInt(this, &CursorPos, 0L);
+			bModified = true;		fmt_txt->cur_right(&CursorPos);			ShowCursor(o);
+			return true;
+			}
+		return false;
+	case CMD_ADDCHAR:
+		SetModified();
+		if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
+		//value 8 == backspace
+	case CMD_BACKSP:
+		SetModified();
+		if(CursorPos <=0 && o) {
+			if(parent->Id == GO_MLABEL) {
+				parent->Command(CMD_SETFOCUS, this, o);
+				return parent->Command(CMD_BACKSP, tmpl, o);
+				}
+			RedrawEdit(o);
+			return true;
+			}
+		Undo.ValInt(this, &CursorPos, 0L);
+		CursorPos--;							//continue as if delete
+	case CMD_DELETE:
+		SetModified();
+		if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, 0L);
+		if(TextDef.text && TextDef.text[CursorPos]) {
+			Undo.String(this, &TextDef.text, UNDO_CONTINUE);
+			rlp_strcpy(TextDef.text + CursorPos, TMP_TXT_SIZE, TextDef.text + CursorPos + 1);
+			if(o)RedrawEdit(o);
+			}
+		else if(TextDef.text && parent->Id == GO_MLABEL) {
+			parent->Command(CMD_SETFOCUS, this, o);
+			return parent->Command(CMD_DELETE, tmpl, o);
+			}
+		else o->HideMark();
+		break;
+	case CMD_GETTEXT:
+		if(TextDef.text && TextDef.text[0] && tmpl) {
+			rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, TextDef.text);
+			return true;
+			}
+		return false;
+	case CMD_SETTEXT:
+		if(TextDef.text) free(TextDef.text);		TextDef.text = 0L;
+		if(tmpl && *((char*)tmpl)) {
+			TextDef.text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+			}
+		return true;
+	case CMD_GETTEXTDEF:
+		if(!tmpl) return false;
+		memcpy(tmpl, &TextDef, sizeof(TextDEF));
+		return true;
+	case CMD_SETTEXTDEF:
+		if(!tmpl)return false;
+		memcpy(&TextDef, tmpl, sizeof(TextDEF)-sizeof(char*));
+		if(((TextDEF*)tmpl)->text) Command(CMD_SETTEXT, tmpl, o);
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_LABEL;
+		data = (DataObj*)tmpl;
+		return true;
+	case CMD_UPDATE:
+		if(ssRef && cssRef >2 && data) {
+			data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+			data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+			if(data->GetText(ssRef[2].y, ssRef[2].x, TmpTxt, TMP_TXT_SIZE)) {
+				Undo.String(this, &TextDef.text, UNDO_CONTINUE);
+				TextDef.text = (char*)realloc(TextDef.text, cb = (int)strlen(TmpTxt)+2);
+				if(TmpTxt[0]) rlp_strcpy(TextDef.text, cb, TmpTxt);
+				else TextDef.text[0] = 0;
+				}
+			return true;
+			}
+		return false;
+	case CMD_SELECT:
+		if(!o || !tmpl) return false;
+		CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
+		o->ShowMark(this, MRK_GODRAW);
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(ObjThere(mev->x, mev->y)) {
+				if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
+				CalcCursorPos(mev->x, mev->y, o);
+				o->ShowMark(this, MRK_GODRAW);
+				return true;
+				}
+			break;
+			}
+		break;
+	case CMD_AUTOSCALE:
+		if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+			&& (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
+			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+			return true;
+			}
+		break;
+	case CMD_REDRAW:
+		if(is3D && o) {
+			DoPlotText(o);
+			is3D = false;										//enable edit
+			}
+		else if(CurrGO == this) {
+			if(parent && parent->parent) RedrawEdit(defDisp);	//not a dialog
+			else ShowCursor(defDisp);							//dialog !
+			}
+		else return parent->Command(cmd, tmpl, o);
+		return true;
+	case CMD_MOVE:
+		if(parent && (parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM))
+			return parent->Command(cmd, tmpl, o);
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		if(fmt_txt) delete(fmt_txt);	fmt_txt = 0L;
+		if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
+		if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
+		if(o){
+			o->StartPage();		parent->DoPlot(o);		o->EndPage();
+			}
+		return bModified = true;
+		}
+	return false;
+}
+
+void *
+Label::ObjThere(int x, int y)
+{
+	POINT p1;
+
+	if(IsInRect(&rDims, p1.x = x, p1.y = y) && IsInPolygon(&p1, pts, 5))
+		return this;
+	return 0L;
+}
+
+void
+Label::Track(POINT *p, anyOutput *o)
+{
+	POINT *tpts;
+	RECT old_rc;
+	int i;
+
+	if(!parent) return;
+	if(parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM){
+		parent->Track(p, o);
+		return;
+		}
+	if(o && (tpts = (POINT*)malloc(5*sizeof(POINT)))){
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		//note: mLabel set Id to zero upon trackking
+		//   thus rectangle is not updated if parent is a mLabel
+		if(parent->Id) o->UpdateRect(&rDims, false);
+		for(i = 0; i < 5; i++) {
+			tpts[i].x = pts[i].x+p->x;	tpts[i].y = pts[i].y+p->y;
+			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+			}
+		o->ShowLine(tpts, 5, TextDef.ColTxt);
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		free(tpts);
+		}
+}
+
+bool
+Label::CalcRect(anyOutput *o)
+{
+	int rx1, rx, ry;
+	fRECT rc, rcc;
+
+	if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
+	if(fmt_txt && TextDef.text && TextDef.text[0]) {
+		fmt_txt->SetText(0L, TextDef.text, &ix, &iy);
+		if(!(fmt_txt->oGetTextExtent(o, &rx, &ry, 0))) return false;
+		rx++;
+		}
+	else {
+		if(!(o->oGetTextExtent("A", 1, &rx, &ry))) return false;
+		rx = 1;
+		}
+	rx += 4;	rc.Xmin = -2.0f;	rc.Ymin = 0.0f;		rc.Xmax = rx;		rc.Ymax = ry;
+	si = sin(TextDef.RotBL *0.01745329252);	csi = cos(TextDef.RotBL *0.01745329252);
+	if(TextDef.Align & TXA_HCENTER) {
+		rc.Xmin -= rx/2.0-1.0;		rc.Xmax -= rx/2.0-1.0;
+		}
+	else if(TextDef.Align & TXA_HRIGHT) {
+		rc.Xmin -= rx-2.0;			rc.Xmax -= rx-2.0;
+		}
+	if(TextDef.Align & TXA_VCENTER) {
+		rc.Ymin -= ry/2.0;			rc.Ymax -= ry/2.0;
+		}
+	else if(TextDef.Align & TXA_VBOTTOM) {
+		rc.Ymin -= ry;				rc.Ymax -= ry;
+		}
+	if(fmt_txt && fmt_txt->oGetTextExtent(o, &rx1, &ry, CursorPos)){
+		rx = CursorPos ? (int)rx1 : 0;
+		}
+	else rx = 0;
+	rcc.Xmax = rc.Xmin + (double)rx+2.0;	rcc.Ymin = rc.Ymin+2.0;
+	rcc.Xmin = rc.Xmin;						rcc.Ymax = rc.Ymax-2.0;
+	pts[0].x = iround(rc.Xmin*csi + rc.Ymin*si)+ix;
+	pts[0].y = iround(rc.Ymin*csi - rc.Xmin*si)+iy;
+	pts[1].x = iround(rc.Xmax*csi + rc.Ymin*si)+ix;
+	pts[1].y = iround(rc.Ymin*csi - rc.Xmax*si)+iy;
+	pts[2].x = iround(rc.Xmax*csi + rc.Ymax*si)+ix;
+	pts[2].y = iround(rc.Ymax*csi - rc.Xmax*si)+iy;
+	pts[3].x = iround(rc.Xmin*csi + rc.Ymax*si)+ix;
+	pts[3].y = iround(rc.Ymax*csi - rc.Xmin*si)+iy;
+	pts[4].x = pts[0].x;	pts[4].y = pts[0].y;
+	Cursor.left = iround(rcc.Xmax*csi + rcc.Ymin*si)+ix;
+	Cursor.top = iround(rcc.Ymin*csi - rcc.Xmax*si)+iy;
+	Cursor.right = iround(rcc.Xmax*csi + rcc.Ymax*si)+ix;
+	Cursor.bottom = iround(rcc.Ymax*csi - rcc.Xmax*si)+iy;
+	return true;
+}
+
+void 
+Label::RedrawEdit(anyOutput *o)
+{
+	FillDEF bgFill = {FILL_NONE, bgcolor, 1.0, 0L, bgcolor};
+
+	if(!o || !parent) return;
+	bgLine.color = bgcolor;		o->SetLine(&bgLine);	o->SetFill(&bgFill);
+	o->oPolygon(pts, 5);		IncrementMinMaxRect(&rDims, 3);		
+	o->UpdateRect(&rDims, false);
+	CalcRect(o);				bgLine.color ^= 0x00ffffffL;
+	o->SetLine(&bgLine);		o->oPolygon(pts, 5);
+	if(parent->Id == GO_MLABEL) {
+		if(parent->parent && parent->parent->Id == GO_LEGITEM && parent->parent->parent)
+			parent->parent->parent->DoPlot(o);
+		else parent->DoPlot(o);
+		}
+	else if(parent->Id == GO_LEGITEM && parent->parent) parent->parent->DoPlot(o);
+	else DoPlot(o);
+	o->UpdateRect(&rDims, false);
+	DoMark(o, true);			ShowCursor(o);
+}
+
+void
+Label::SetModified()
+{
+	AxisDEF *adef;
+
+	bModified = true;
+	if(parent && parent->Id==GO_TICK && parent->parent && parent->parent->Id==GO_AXIS){
+	adef = ((Axis*)(parent->parent))->GetAxis();
+	adef->flags &= ~AXIS_AUTOSCALE;
+	}
+}
+
+void
+Label::DoPlotText(anyOutput *o)
+{
+	if(!parent || !o) return;
+	defDisp = o;
+	if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
+	switch(flags & 0x03) {
+	case LB_X_DATA:	ix = o->fx2ix(fPos.fx);		break;
+	case LB_X_PARENT: 
+		ix = iround(parent->GetSize(SIZE_LB_XPOS));
+		break;
+	default:
+		ix = o->co2ix(fPos.fx + parent->GetSize(SIZE_GRECT_LEFT));
+		break;
+		}
+	switch(flags & 0x30) {
+	case LB_Y_DATA:	iy = o->fy2iy(fPos.fy);		break;
+	case LB_Y_PARENT: 
+		iy = iround(parent->GetSize(SIZE_LB_YPOS));
+		break;
+	default:
+		iy = o->co2iy(fPos.fy +parent->GetSize(SIZE_GRECT_TOP));
+		break;
+		}
+	ix += o->un2ix(fDist.fx);		iy += o->un2iy(fDist.fy);
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+	o->SetTextSpec(&TextDef);
+	if(TextDef.text && TextDef.text[0]){
+		if(fmt_txt) fmt_txt->SetText(o, TextDef.text, &ix, &iy);
+		else fmt_txt = new fmtText(o, ix, iy, TextDef.text);
+		}
+	if(!(CalcRect(o))) return;
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
+	UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a multiline label consists of several Label objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt, 
+	int cp, DWORD flg):GraphObj(par, d)
+{
+	int i;
+
+	memcpy(&TextDef, td, sizeof(TextDEF));
+	TextDef.text = 0L;		fPos.fx = x;		fPos.fy = y;
+	Lines = 0L;				flags = flg;		lspc = 1.0;
+	fDist.fx = 0.0;			fDist.fy = 0.0;
+	CurrGO = CurrLabel = 0L;
+	if(txt && (Lines = (Label**)calloc(2, sizeof(Label*)))) {
+		for(i = 0; i < cp && txt[i]; i ++) TmpTxt[i] = txt[i];
+		TmpTxt[i] = 0;
+		if(Lines[0] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT))
+			Lines[0]->Command(CMD_SETTEXT, TmpTxt, 0L);
+		if(Lines[1] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
+			Lines[1]->Command(CMD_SETTEXT, txt+cp, 0L);
+			CurrGO = CurrLabel = Lines[1];
+			}
+		nLines = 2;		cli = 1;
+		}
+	Id = GO_MLABEL;
+}
+
+mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt)
+	:GraphObj(par, d)
+{
+	int i, nll;
+	char **llist;
+
+	memcpy(&TextDef, td, sizeof(TextDEF));
+	TextDef.text = 0L;		fPos.fx = x;		fPos.fy = y;
+	Lines = 0L;				flags = 0L;			Id = GO_MLABEL;
+	fDist.fx = 0.0;			fDist.fy = 0.0;		lspc = 1.0;
+	CurrGO = CurrLabel = 0L;
+	if(txt){
+		if((llist=split(txt,'\n',&nll)) && nll && (Lines=(Label**)calloc(nll, sizeof(Label*)))){
+			for(i = 0; i < nll; i++) {
+				if(llist[i]){
+					Lines[i] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT);
+					Lines[i]->Command(CMD_SETTEXT, llist[i], 0L);
+					free(llist[i]);
+					}
+				}
+			free(llist);	nLines = nll;		cli = 0;
+			}
+		}
+}
+
+mLabel::mLabel(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+mLabel::~mLabel()
+{
+	int i;
+	
+	Undo.InvalidGO(this);
+	if(Lines){
+		for(i = 0; i < nLines; i++) if(Lines[i]) DeleteGO(Lines[i]);
+		free(Lines);
+		}
+}
+
+double
+mLabel::GetSize(int select)
+{
+	switch(select){
+	case SIZE_LB_XPOS:	return cPos1.fx;
+	case SIZE_LB_YPOS:	return cPos1.fy;
+	case SIZE_GRECT_TOP:	
+		if (parent) return parent->GetSize(select);
+		break;
+	case SIZE_MIN_Z:	case SIZE_MAX_Z:	case SIZE_ZPOS:
+		return curr_z;
+	case SIZE_LSPC:
+		return lspc;
+		}
+	return 0.0;
+}
+
+bool
+mLabel::SetSize(int select, double value)
+{
+	int i;
+
+	switch(select & 0xfff) {
+	case SIZE_LB_XDIST:
+		undo_flags = CheckNewFloat(&fDist.fx, fDist.fx, value, this, undo_flags);
+		return true;
+	case SIZE_LB_YDIST:
+		undo_flags = CheckNewFloat(&fDist.fy, fDist.fy, value, this, undo_flags);
+		return true;
+	case SIZE_XPOS:
+		undo_flags = CheckNewFloat(&fPos.fx, fPos.fx, value, this, undo_flags);
+		return true;
+	case SIZE_YPOS:
+		undo_flags = CheckNewFloat(&fPos.fy, fPos.fy, value, this, undo_flags);
+		return true;
+	case SIZE_ZPOS:
+		curr_z = value;
+		if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]){
+			Lines[i]->SetSize(select, value);
+			}
+		return is3D = true;
+	case SIZE_LSPC:
+		undo_flags = CheckNewFloat(&lspc, lspc, value, this, undo_flags);
+		return true;
+		}
+	return false;
+}
+
+void
+mLabel::DoPlot(anyOutput *o)
+{
+	int i;
+	double dh, dx, dy;
+
+	if(!o || !Lines) return;
+	undo_flags = 0L;
+	if(parent){		//if this object is part of a dialog we dont have a parent
+		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+		}
+	else dx = dy = 0.0;
+	cPos.fx = cPos.fy = 0.0;
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+	switch(flags & 0x03) {
+	case LB_X_DATA:		cPos.fx = o->fx2fix(fPos.fx);				break;
+	case LB_X_PARENT:	if(parent) cPos.fx = parent->GetSize(SIZE_LB_XPOS);	break;
+	default:
+		//if no parent its a dialog
+		cPos.fx = parent ? o->co2fix(fPos.fx + dx) : fPos.fx;
+		break;
+		}
+	switch(flags & 0x30) {
+	case LB_Y_DATA:		cPos.fy = o->fy2fiy(fPos.fy);				break;
+	case LB_Y_PARENT:	if(parent) cPos.fy = parent->GetSize(SIZE_LB_YPOS);	break;
+	default:	
+		//if no parent its a dialog
+		cPos.fy = parent ? o->co2fiy(fPos.fy + dy) : fPos.fy;
+		break;
+		}
+	si = sin(TextDef.RotBL *0.01745329252f);	csi = cos(TextDef.RotBL *0.01745329252f);
+	if(TextDef.Align & TXA_VBOTTOM) dh = (double)(nLines-1);
+	else if(TextDef.Align & TXA_VCENTER) dh = ((double)(nLines-1))/2.0;
+	else dh = 0.0;						dh *= TextDef.fSize;
+	cPos.fx -= o->un2fix(dh*si);		cPos.fy -= o->un2fiy(dh*csi);
+	memcpy(&cPos1, &cPos, sizeof(lfPOINT));
+	if(lspc < 0.5 || lspc > 5) lspc = 1.0;
+#ifdef _WINDOWS
+	dist.fx = floor(o->un2fix(TextDef.fSize * si * lspc));
+	dist.fy = floor(o->un2fiy(TextDef.fSize * csi * lspc));
+#else
+	dist.fx = floor(o->un2fix(TextDef.fSize * si * 1.2 * lspc));
+	dist.fy = floor(o->un2fiy(TextDef.fSize * csi * 1.2 * lspc));
+#endif
+	o->SetTextSpec(&TextDef);
+	rDims.left = rDims.top = rDims.right = rDims.bottom = 0;
+	for(i = 0; i < nLines; i++)	if(Lines[i]){
+		Lines[i]->Command(CMD_SETTEXTDEF, &TextDef, o);
+		Lines[i]->SetSize(SIZE_LB_XDIST, fDist.fx);	Lines[i]->SetSize(SIZE_LB_YDIST, fDist.fy);
+		Lines[i]->SetSize(SIZE_XPOS, fPos.fx);		Lines[i]->SetSize(SIZE_YPOS, fPos.fy);
+		Lines[i]->moveable = moveable;				Lines[i]->DoPlot(o);
+		UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
+		UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
+		}
+	if(CurrLabel && o && Command(CMD_SETFOCUS, CurrLabel, o))
+		Lines[cli]->ShowCursor(o);
+}
+
+bool
+mLabel::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i, j, k;
+	fRECT t_cur;
+	MouseEvent mev;
+	scaleINFO *scale;
+
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		if(Lines && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) 
+			for(i = 0; i<nLines; i++) if(Lines[i] && Lines[i]->Command(cmd, tmpl, o)) return true;
+		break;
+	case CMD_HIDE_MARK:
+		if(Lines && o && tmpl) for(i = 0; i< nLines; i++) 
+			if(Lines[i] && tmpl == (void*)Lines[i]){
+				Lines[i]->DoMark(o, false);
+				return true;
+				}
+		return false;
+	case CMD_ADDCHAR:
+		if(!tmpl || 13 != *((int*)tmpl)) return false;
+		if(!Lines[cli] || !Lines[cli]->Command(CMD_GETTEXT, &TmpTxt, o)) return false;
+		k = iround(Lines[cli]->GetSize(SIZE_CURSORPOS));
+		if(parent)Undo.ObjConf(this, 0L);
+		if(tmpl && Lines && (Lines = (Label**)realloc(Lines, (nLines+1) * sizeof(Label*)))) {
+			for(i = nLines-1, j = nLines; i >= cli; i--, j-- ) {
+				Lines[j] = Lines[i];
+				}
+			i++, j++;
+			if(Lines[j]) DeleteGO(Lines[j]);	Lines[i] = Lines[j] = 0L;	nLines++;
+			if(Lines[j] = new 	Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
+				Lines[j]->Command(CMD_SETTEXT, TmpTxt+k, o);
+				Lines[j]->Command(CMD_POS_FIRST, 0L, o);
+				CurrGO = CurrLabel = Lines[j];
+				TmpTxt[k] = 0;
+				}
+			if(Lines[i] = new 	Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT))
+				Lines[i]->Command(CMD_SETTEXT, TmpTxt, 0L);
+			Command(CMD_SETFOCUS, CurrGO, o);
+			if(parent) return parent->Command(CMD_REDRAW, 0L, o);
+			else if(o) DoPlot(o);
+			}
+		break;
+	case CMD_SETFOCUS:
+		for(i = 0; i< nLines; i++) if(Lines[i] == (Label*)tmpl) {
+			cli = i;
+			cPos1.fx = cPos.fx + dist.fx*i;
+			cPos1.fy = cPos.fy + dist.fy*i;
+			return true;
+			}
+		break;
+	case CMD_GETTEXT:
+		if(tmpl && Lines && nLines && Lines[0]) return Lines[0]->Command(CMD_GETTEXT, tmpl, o);
+		break;
+	case CMD_ALLTEXT:							//used e.g from dialog text boxes
+		if(tmpl && Lines && nLines){
+			for(i = j = 0; i < nLines; i++) {
+				if(Lines[i] && Lines[i]->Command(CMD_GETTEXT, TmpTxt+500, o) && TmpTxt[500]){
+					j += rlp_strcpy((char*)tmpl+j, 500-j, TmpTxt+500);
+					((char*)tmpl)[j++] = '\n';
+					}
+				((char*)tmpl)[j] = 0;
+				}
+			if(j >2) return true;
+			}
+		return false;
+	case CMD_DELETE:
+		cli++;
+		//fall through
+	case CMD_BACKSP:
+		if(cli > 0 && cli < nLines && Lines && Lines[cli] && Lines[cli-1]) {
+			Lines[cli-1]->Command(CMD_POS_LAST, 0L, o);
+			TmpTxt[0] = 0;
+			Lines[cli-1]->Command(CMD_GETTEXT, TmpTxt, o);
+			Lines[cli]->Command(CMD_GETTEXT, TmpTxt+strlen(TmpTxt), o);
+			Lines[cli-1]->Command(CMD_SETTEXT, TmpTxt, o);
+			DeleteGO(Lines[cli]);	Lines[cli] = 0L;
+			for(i = cli+1; i < nLines; i++){
+				Lines[i-1] = Lines[i], Lines[i]= 0L;
+				}
+			nLines--;
+			CurrGO = CurrLabel = Lines[cli-1];
+			if(parent) parent->Command(CMD_REDRAW, 0L, o);
+			if(CurrLabel) CurrLabel->RedrawEdit(o);
+			return true;
+			}
+		return false;
+	case CMD_GETTEXTDEF:
+		if(!tmpl) return false;
+		memcpy(tmpl, &TextDef, sizeof(TextDEF));
+		return true;
+	case CMD_SETTEXTDEF:
+		if(!tmpl)return false;
+		if(parent)Undo.TextDef(this, &TextDef, undo_flags);
+		undo_flags |= UNDO_CONTINUE;
+		memcpy(&TextDef, tmpl, sizeof(TextDEF));
+		TextDef.text = 0L;
+		return true;
+	case CMD_SET_DATAOBJ:
+		if(Lines) {
+			for(i = 0; i< nLines; i++) if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
+			}
+		Id = GO_MLABEL;
+		data = (DataObj*)tmpl;
+		return true;
+	case CMD_AUTOSCALE:
+		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+			&& (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
+			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+			return true;
+			}
+		break;
+	case CMD_CURRUP:		case CMD_CURRDOWN:
+		if(!o) return false;
+		o->SetTextSpec(&TextDef);
+		Command(CMD_SETFOCUS, CurrGO, o);
+		if(cli >= 0 && cli < nLines && Lines && Lines[cli]) {
+			t_cur.Xmin = Lines[cli]->GetSize(SIZE_CURSOR_XMIN);
+			t_cur.Xmax = Lines[cli]->GetSize(SIZE_CURSOR_XMAX);
+			t_cur.Ymin = Lines[cli]->GetSize(SIZE_CURSOR_YMIN);
+			t_cur.Ymax = Lines[cli]->GetSize(SIZE_CURSOR_YMAX);
+			mev.StateFlags = 0;		mev.Action = MOUSE_LBUP;
+			mev.x = iround((t_cur.Xmax+t_cur.Xmin)/2.0);
+			mev.y = iround((t_cur.Ymax+t_cur.Ymin)/2.0);
+			i = o->un2ix(TextDef.fSize*si);		j = o->un2iy(TextDef.fSize*csi);
+			if(cmd == CMD_CURRUP && cli > 0 && Lines[cli-1]) {
+				Lines[cli-1]->CalcCursorPos(mev.x -= i, mev.y -= j, o);
+				o->ShowMark(CurrGO = CurrLabel = Lines[cli-=1], MRK_GODRAW);
+				return Command(CMD_SETFOCUS, Lines[cli], o);
+				}
+			if(cmd == CMD_CURRDOWN && cli < (nLines-1) && Lines[cli+1]) {
+				Lines[cli+1]->CalcCursorPos(mev.x += i, mev.y += j, o);
+				o->ShowMark(CurrGO = CurrLabel = Lines[cli+=1], MRK_GODRAW);
+				return Command(CMD_SETFOCUS, Lines[cli], o);
+				}
+			}
+		else return false;
+		break;
+	case CMD_SCALE:
+		scale = (scaleINFO*)tmpl;
+		if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
+		if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
+		fDist.fx *= scale->sx.fy;				fDist.fy *= scale->sy.fy;
+		TextDef.fSize *= scale->sx.fy;			TextDef.iSize = 0;
+		return true;
+	case CMD_SELECT:
+		if(o && tmpl) for(i = 0; i < nLines; i++){
+			o->SetTextSpec(&TextDef);
+			if(Lines[i] && ((POINT*)tmpl)->y > Lines[i]->rDims.top && ((POINT*)tmpl)->y < 
+				Lines[i]->rDims.bottom) return Lines[i]->Command(cmd, tmpl, o);
+			}
+		break;
+	case CMD_DELOBJ:
+		if(parent && Lines) for(i = 0; i< nLines; i++) 
+			if(Lines[i] && Lines[i] == (Label*)tmpl) return parent->Command(cmd, this, o);
+		break;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		else if(o) DoPlot(o);
+		break;
+	case CMD_MOVE:
+		if(parent && parent->Id == GO_LEGITEM) return parent->Command(cmd, tmpl, o);
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
+		if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
+		if(o && parent){
+			o->StartPage();		parent->DoPlot(o);		o->EndPage();
+			}
+		return true;
+		}
+	return false;
+}
+
+void
+mLabel::Track(POINT *p, anyOutput *o)
+{
+	int i;
+
+	if(!parent) return;
+	if(parent->Id == GO_LEGITEM){
+		parent->Track(p, o);
+		return;
+		}
+	for(i = 0; i < nLines; i++)	if(Lines[i]){
+		if(!i) memcpy(&rDims, &Lines[i]->rDims, sizeof(RECT));
+		else {
+			UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
+			UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
+			}
+		}
+	o->UpdateRect(&rDims, false);
+	Id = 0L;			//disable reentrance from Label objects
+	for(i = 0; i < nLines; i++)	if(Lines[i]) Lines[i]->Track(p, o);
+	Id = GO_MLABEL;		//enable entrance from Label objects
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a rectangular range to accept any text
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TextFrame::TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt)
+	:GraphObj(parent, data)
+{
+	FileIO(INIT_VARS);					lspc = 1.0;
+	pos1.fx = p1->fx;	pos1.fy = p1->fy;	pos2.fx = p2->fx;	pos2.fy = p2->fy;
+	if(txt && txt[0]) {
+		text = (unsigned char*)memdup(txt, (int)strlen(txt)+1, 0);
+		}
+	else if(lines = (unsigned char**)malloc(sizeof(char*))){
+		if(lines[0] = (unsigned char*)malloc(TF_MAXLINE))lines[0][0] = 0;
+		nlines = 1;
+		}
+	Id = GO_TEXTFRAME;
+}
+
+TextFrame::TextFrame(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	moveable = 1;				bModified = false;
+}
+
+TextFrame::~TextFrame()
+{
+	int i;
+
+	if(text)free(text);			text = 0L;
+	if(drc) delete(drc);		drc = 0L;
+	if(tm_rec) free(tm_rec);	tm_rec = 0L;
+	if(lines) {
+		for(i = 0; i < nlines; i++)	if(lines[i]) free(lines[i]);
+		free(lines);			lines = 0L;
+		}
+	HideTextCursor();
+}
+double
+TextFrame::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XPOS:		return pos1.fx;
+	case SIZE_XPOS+1:	return pos2.fx;
+	case SIZE_YPOS:		return pos1.fy;
+	case SIZE_YPOS+1:	return pos2.fy;
+	case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
+	case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
+		if(parent) return parent->GetSize(select);
+		break;
+		}
+	return 0.0;
+}
+
+bool
+TextFrame::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_XPOS:				pos1.fx = value;			return bResize = true;
+	case SIZE_XPOS+1:			pos2.fx = value;			return bResize = true;
+	case SIZE_YPOS:				pos1.fy = value;			return bResize = true;
+	case SIZE_YPOS+1:			pos2.fy = value;			return bResize = true;
+		}
+	return false;
+}
+
+void 
+TextFrame::DoMark(anyOutput *o, bool mark)
+{
+	RECT upd;
+
+	if(has_m1 && has_m2) TextMark(o, 3);
+	has_m1 = has_m2 = false;
+	if(!drc) drc = new dragRect(this, 0);
+	memcpy(&upd, &rDims, sizeof(RECT));
+	if(mark){
+		if(drc) drc->DoPlot(o);								ShowCursor(o);
+		}
+	else if(parent)	parent->DoPlot(o);
+	IncrementMinMaxRect(&upd, 6);
+	o->UpdateRect(&upd, false);
+}
+
+void
+TextFrame::DoPlot(anyOutput *o)
+{
+	int i, j, x1, y1, x2, y2;
+	double tmp, dx, dy;
+
+	if(!o) return;
+	if(parent){		//if this object is part of a dialog we dont have a parent
+		dx = parent->GetSize(SIZE_GRECT_LEFT);			dy = parent->GetSize(SIZE_GRECT_TOP);
+		x1 = o->co2ix(pos1.fx+dx);						y1 = o->co2iy(pos1.fy+dy);
+		x2 = o->co2ix(pos2.fx+dx);						y2 = o->co2iy(pos2.fy+dy);
+		ipad.left = o->un2ix(pad.Xmin);					ipad.right = o->un2ix(pad.Xmax);
+		ipad.top = o->un2iy(pad.Ymin);					ipad.bottom = o->un2iy(pad.Ymax);
+		}
+	else {
+		dx = dy = 0.0;
+		x1 = (int)pos1.fx;		y1 = (int)pos1.fy;		x2 = (int)pos2.fx;		y2 = (int)pos2.fy;
+		ipad.left = ipad.right = ipad.top = ipad.bottom = 4;
+		fmt_txt.EditMode(true);
+		}
+	if(pos1.fx > pos2.fx) {
+		tmp = pos2.fx;	pos2.fx = pos1.fx;	pos1.fx = tmp;
+		}
+	if(pos1.fy > pos2.fy) {
+		tmp = pos2.fy;	pos2.fy = pos1.fy;	pos1.fy = tmp;
+		}
+	o->SetLine(&Line);						o->SetFill(&Fill);
+	o->oRectangle(x1, y1, x2, y2, name);
+	SetMinMaxRect(&rDims, x1, y1, x2, y2);
+	x1 += ipad.left;						y1 += ipad.top;
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+#ifdef _WINDOWS
+	linc = o->un2iy(TextDef.fSize*lspc);
+#else
+	linc = o->un2iy(TextDef.fSize*lspc*1.2);
+#endif
+	o->SetTextSpec(&TextDef);				y1 += linc;
+	if(text && text[0] && !(lines)) text2lines(o);
+	else if(bResize && lines) {
+		c_char = lines[cur_pos.y][cur_pos.x];			lines[cur_pos.y][cur_pos.x] = 0x01;
+		if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00; 
+		lines2text();				text2lines(o);		bResize = false;
+		o->ShowMark(this, MRK_GODRAW);
+		return;
+		}
+	if(has_m1 && has_m2) TextMark(o, 1);
+	for(i = 0; i < nlines; i++) {
+		if(lines[i] && lines[i][0]){
+			j = (int)strlen((char*)lines[i]);
+			if(lines[i][j-1] == '\n') {
+				lines[i][j-1] = 0;
+				fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
+				lines[i][j-1] = '\n';
+				}
+			else fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
+			}
+		y1 += linc;
+		}
+	if(has_m1 && has_m2) TextMark(o, 2);
+	bModified = bResize = false;
+}
+
+bool
+TextFrame::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	int i;
+
+	switch (cmd) {
+	case CMD_SELECT:
+		if(!o || !tmpl) return false;
+		CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
+		if(parent)o->ShowMark(this, MRK_GODRAW);	ShowCursor(o);
+		return true;
+	case CMD_COPY:
+		return CopyText(o, false);
+	case CMD_SAVEPOS:
+		bModified = true;
+		Undo.SaveLFP(this, &pos1, 0L);
+		Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
+		return true;
+	case CMD_SCALE:
+		if(tmpl) {
+			pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
+			pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
+			pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
+			pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
+			TextDef.fSize *= ((scaleINFO*)tmpl)->sy.fy;		TextDef.iSize = 0;
+			pad.Xmax *= ((scaleINFO*)tmpl)->sx.fy;			pad.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+			pad.Ymax *= ((scaleINFO*)tmpl)->sy.fy;			pad.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+			Line.width *= ((scaleINFO*)tmpl)->sy.fy;		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+			FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;	FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+			Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+			}
+		return true;
+	case CMD_GETTEXT:	case CMD_ALLTEXT:
+		if(lines && lines[0] && lines[0][0] && nlines) {
+			lines2text();	i = rlp_strcpy((char*)tmpl, TMP_TXT_SIZE-2, (char*)text);
+			while(i && ((char*)tmpl)[i-1] == '\n') i--; 
+			((char*)tmpl)[i++] = '\n';						((char*)tmpl)[i] = 0;
+			return true;
+			}
+		return false;
+	case CMD_ADDCHAR:
+		if(tmpl && o) AddChar(o, *((unsigned char*)tmpl));
+		return true;
+	case CMD_DELETE:
+		if(o) DelChar(o);
+		return true;
+	case CMD_SHIFTLEFT:
+		if(!has_m1) {
+			m1_pos.x = cur_pos.x;		m1_pos.y = cur_pos.y;
+			}
+		has_m1 = has_m2 = true;
+	case CMD_CURRLEFT:
+		if(!(lines[cur_pos.y]))return false;
+		if(cmd == CMD_CURRLEFT && has_m1 && has_m2) TextMark(o, 3);
+		if(cur_pos.x > 0) {
+			i = 0;					fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
+			i = cur_pos.x;			fmt_txt.cur_left(&i);
+			cur_pos.x = i;
+			}
+		else if(cur_pos.y) {
+			cur_pos.y--;			cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
+			}
+		if(cmd == CMD_SHIFTLEFT){
+			m2_pos.x = cur_pos.x;		m2_pos.y = cur_pos.y;
+			DoPlot(o);					o->UpdateRect(&rDims, false);
+			}
+		ShowCursor(o);
+		return false;
+	case CMD_SHIFTRIGHT:
+		if(!has_m1) {
+			m1_pos.x = cur_pos.x;		m1_pos.y = cur_pos.y;
+			}
+		has_m1 = has_m2 = true;
+	case CMD_CURRIGHT:
+		if(!(lines[cur_pos.y]))return false;
+		if(cmd == CMD_CURRIGHT && has_m1 && has_m2) TextMark(o, 3);
+		if(cur_pos.x >= (int)strlen((char*)lines[cur_pos.y])) {
+			if(cur_pos.y < (nlines-1)) {
+				cur_pos.y++;		cur_pos.x = 0;
+				}
+			else if(cur_pos.y == (nlines-1) && lines[cur_pos.y][0]) {
+				if(!(lines = (unsigned char**)realloc(lines, (nlines+1)*sizeof(char*))))return false;
+				if(!(lines[cur_pos.y+1] = (unsigned char*)malloc(TF_MAXLINE))) return false;
+				cur_pos.y++;		cur_pos.x = 0;		nlines++;
+				lines[cur_pos.y][0] = 0;
+				}
+			}
+		else {
+			i = 0;						fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
+			i = cur_pos.x;				fmt_txt.cur_right(&i);
+			cur_pos.x = i;
+			}
+		if(cmd == CMD_SHIFTRIGHT){
+			m2_pos.x = cur_pos.x;		m2_pos.y = cur_pos.y;
+			DoPlot(o);					o->UpdateRect(&rDims, false);
+			}
+		ShowCursor(o);
+		return false;
+	case CMD_SHIFTUP:
+		if(!has_m1) {
+			m1_pos.x = cur_pos.x;		m1_pos.y = cur_pos.y;
+			}
+		has_m1 = has_m2 = true;
+	case CMD_CURRUP:
+		if(cmd == CMD_CURRUP && has_m1 && has_m2) TextMark(o, 3);
+		if(cur_pos.y && o) {
+			i = ((Cursor.bottom + Cursor.top)>>1)-linc;
+			CalcCursorPos(Cursor.left, i, o);
+			if(cmd == CMD_SHIFTUP){
+				m2_pos.x = cur_pos.x;	m2_pos.y = cur_pos.y;
+				DoPlot(o);				o->UpdateRect(&rDims, false);
+				}
+			ShowCursor(o);
+			return true;
+			}
+		return false;
+	case CMD_SHIFTDOWN:
+		if(!has_m1) {
+			m1_pos.x = cur_pos.x;		m1_pos.y = cur_pos.y;
+			}
+		has_m1 = has_m2 = true;
+	case CMD_CURRDOWN:
+		if(cmd == CMD_CURRDOWN && has_m1 && has_m2) TextMark(o, 3);
+		if(cur_pos.y < (nlines-1) && o && lines[cur_pos.y][0]) {
+			i = ((Cursor.bottom + Cursor.top)>>1)+linc;
+			if(i >= (rDims.bottom-ipad.bottom)) return false;
+			CalcCursorPos(Cursor.left, i, o);
+			if(cmd == CMD_SHIFTDOWN){
+				m2_pos.x = cur_pos.x;	m2_pos.y = cur_pos.y;
+				DoPlot(o);				o->UpdateRect(&rDims, false);
+				}
+			ShowCursor(o);
+			return true;
+			}
+		return false;
+	case CMD_POS_FIRST:
+		if(has_m1 && has_m2) TextMark(o, 3);
+		cur_pos.x = 0;									ShowCursor(o);
+		return true;
+	case CMD_POS_LAST:
+		if(has_m1 && has_m2) TextMark(o, 3);
+		cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
+		ShowCursor(o);
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && (!(CurrGO) || !has_m2) && o){
+				CalcCursorPos(mev->x, mev->y, o);
+				if(has_m1 && has_m2) {
+					if(o)DoPlot(o);						o->UpdateRect(&rDims, false);
+					CurrGO = this;						ShowCursor(o);
+					return true;
+					}
+				return o->ShowMark(this, MRK_GODRAW);
+				}
+			else if(CurrGO == this && o){
+				ShowCursor(o);
+				return IsInRect(&rDims, mev->x, mev->y);
+				}
+			break;
+		case MOUSE_LBDOWN:
+			if(has_m1 && has_m2) {
+				has_m1 = has_m2 = false;
+				if(o)DoPlot(o);							o->UpdateRect(&rDims, false);
+				}
+			has_m1 = has_m2 = false;
+		case MOUSE_MOVE:
+			if(!(mev->StateFlags & 0x1)) return false;
+			if(!IsInRect(&rDims, mev->x, mev->y))return false;
+			if(!CurrGO) CurrGO = this;
+			CalcCursorPos(mev->x, mev->y, o);
+			if(!has_m1) {
+				m1_pos.x = m2_pos.x = cur_pos.x;		m1_pos.y = m2_pos.y = cur_pos.y;
+				return has_m1 = true;
+				}
+			else if(cur_pos.x != m2_pos.x || cur_pos.y != m2_pos.y) {
+				m2_pos.x = cur_pos.x;					m2_pos.y = cur_pos.y;
+				has_m2 = true;
+				if(o)DoPlot(o);							o->UpdateRect(&rDims, false);
+				return true;
+				}
+			return true;
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_TEXTFRAME;
+		return true;
+	case CMD_PASTE:
+		return DoPaste(o);
+	case CMD_MOVE:
+		bModified = true;
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		pos1.fx += ((lfPOINT*)tmpl)[0].fx;	pos1.fy += ((lfPOINT*)tmpl)[0].fy;
+		pos2.fx += ((lfPOINT*)tmpl)[0].fx;	pos2.fy += ((lfPOINT*)tmpl)[0].fy;
+		CurrGO = this;
+	case CMD_REDRAW:
+		if(parent){
+			if(o && cmd == CMD_REDRAW) DoPlot(o);		//trickle down ?
+			if(!o && cmd == CMD_REDRAW) {
+				//coming from Undo
+				bModified = true;
+				if(lines) {
+					for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+					free(lines);			lines = 0L;
+					}
+				HideTextCursor();			cur_pos.x = cur_pos.y = 0;
+				parent->Command(CMD_REDRAW, tmpl, o);
+				}
+			else parent->Command(CMD_REDRAW, tmpl, o);
+			}
+		return true;
+	case CMD_SETSCROLL:
+		if(parent) return parent->Command(cmd, tmpl, o);
+	case CMD_GETTEXTDEF:
+		if(!tmpl) return false;
+		memcpy(tmpl, &TextDef, sizeof(TextDEF));
+		return true;
+	case CMD_SETTEXTDEF:
+		if(!tmpl)return false;
+		memcpy(&TextDef, tmpl, sizeof(TextDEF));
+		TextDef.text = 0L;
+		return true;
+	case CMD_SETTEXT:
+		if(lines) {
+			for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+			free(lines);			lines = 0L;
+			}
+		if(text) free(text);		text = 0L;
+		if(tmpl && *((char*)tmpl)) text = (unsigned char*)memdup(tmpl, (int)strlen(((char*)tmpl))+1, 0);
+		return true;
+		}
+	return false;
+}
+
+void
+TextFrame::Track(POINT *p, anyOutput *o)
+{
+	POINT tpts[5];
+	RECT old_rc;
+	double dx, dy;
+
+	if(o && parent){
+		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(pos1.fx+dx)+p->x;		
+		tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(pos1.fy+dy)+p->y;
+		tpts[1].y = tpts[2].y = o->co2iy(pos2.fy+dy)+p->y;
+		tpts[2].x = tpts[3].x = o->co2ix(pos2.fx+dx)+p->x;
+		UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
+		UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);	
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		o->ShowLine(tpts, 5, Line.color);
+		}
+}
+
+void *
+TextFrame::ObjThere(int x, int y)
+{
+	if(drc) return drc->ObjThere(x, y);
+	return 0L;
+}
+
+void
+TextFrame::text2lines(anyOutput *o)
+{
+	int i, j, w, h, cl, maxlines, maxw;
+	char tmp_line[TF_MAXLINE];
+	bool hasMark = false;
+
+	if(lines) {
+		for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+		free(lines);			lines = 0L;
+		}
+	has_m1 = has_m2 = false;
+	nlines = 0;
+	if(!text || !text[0]) return;
+	maxlines = (rDims.bottom -rDims.top)/linc +1;
+	maxw = rDims.right - rDims.left - ipad.left - ipad.right;
+	lines = (unsigned char**)calloc(maxlines, sizeof(char*));
+	for(cl = cpos = w = h = 0; cl < maxlines && text[cpos]; cl++) {
+		if(!(lines[cl] = (unsigned char*)malloc(TF_MAXLINE))) return;
+		for(i = 0; text[cpos] && i < TF_MAXLINE; i++) {
+			tmp_line[i] = text[cpos++];				tmp_line[i+1] = 0;
+			fmt_txt.SetText(0L, tmp_line, &w, &h);
+			if(!(fmt_txt.oGetTextExtent(o, &w, &h, i))) break;
+			if(tmp_line[i] == '\n'){
+				break;													//new line character found
+				}
+			if(tmp_line[i] < ' ') switch(tmp_line[i]) {
+				case 0x01:
+					if(c_char == 0 && text[cpos]) c_char = text[cpos++];	//cursor at end of line
+					hasMark = true;				break;
+				case 0x02:	case 0x03:
+					hasMark = true;				break;
+				}
+			else if(w >= maxw){
+				for(j = i; j > (i>>1); j--) {
+					if(tmp_line[j] == ' ' || tmp_line[j] == '-' || tmp_line[j] < ' ') break;
+					}
+				if(j == (i>>1)) {
+					cpos--;							tmp_line[i] = 0;
+					}
+				else {
+					for(tmp_line[j+1] = 0; j < i; j++, cpos--);
+					}
+				break;
+				}
+			}
+		if(i || tmp_line[i] == '\n') rlp_strcpy((char*)lines[cl], TF_MAXLINE, tmp_line);
+		else lines[cl][0] = 0;
+		}
+	nlines = cl;
+	if(hasMark)procTokens();
+}
+
+void
+TextFrame::lines2text()
+{
+	int i;
+
+	if(text) free(text);		cpos = 0;
+	text = (unsigned char*)malloc(csize = 1000);
+	for(i = 0; i < nlines; i++) {
+		if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+		}
+}
+
+void
+TextFrame::AddChar(anyOutput *o, unsigned char c)
+{
+	int i, j, h, w, maxw;
+
+	if(cur_pos.y >= nlines) return;
+	if(!lines || !lines[cur_pos.y]) return;
+	if(c == '\r') c = '\n';
+	if(has_m1 && has_m2){
+		TmpTxt[0] = c;		TmpTxt[1] = 0;
+		if(c == 8) ReplMark(o, "");
+		else if(c >= 32 || c == '\n') ReplMark(o, TmpTxt);
+		return;
+		}
+	else if(!text) {
+		lines2text();
+		Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+		}
+	maxw = rDims.right - rDims.left - ipad.left - ipad.right;
+	i = j = (int)strlen((char*)lines[cur_pos.y])+1;
+	has_m1 = has_m2 = false;
+	if(c >= 32 || c == '\n') {
+		while(j) {
+			lines[cur_pos.y][j] = lines[cur_pos.y][j-1];	j--;
+			if(j == cur_pos.x){
+				lines[cur_pos.y][j] = c;					j = 0;
+				cur_pos.x++;
+				}
+			}
+		fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &j, &j);
+		fmt_txt.oGetTextExtent(o, &w, &h, i);
+		if(w >= maxw || c == '\n' || (c == ' ' && w >=(maxw>>1))) {
+			c_char = lines[cur_pos.y][cur_pos.x];			lines[cur_pos.y][cur_pos.x] = 0x01;
+			if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00; 
+			lines2text();	Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);		text2lines(o);
+			}
+		}
+	else if(c == 8 && (cur_pos.x || cur_pos.y)) {			//Backspace
+		if(!cur_pos.x) Command(CMD_CURRLEFT, 0L, o);
+		Command(CMD_CURRLEFT, 0L, o);						DelChar(o);
+		return;
+		}
+	else return;
+	DoPlot(o);		o->UpdateRect(&rDims, false);			ShowCursor(o);
+}
+
+void
+TextFrame::DelChar(anyOutput *o)
+{
+	int i;
+	if(has_m1 && has_m2){
+		ReplMark(o, "");	return;
+		}
+	if(lines[cur_pos.y][cur_pos.x]) {
+		lines2text();	Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+		for(i = cur_pos.x; ; i++) {
+			if(!(lines[cur_pos.y][i] = lines[cur_pos.y][i+1])) break;
+			}
+		c_char = lines[cur_pos.y][cur_pos.x];			lines[cur_pos.y][cur_pos.x] = 0x01;
+		if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00; 
+		lines2text();			text2lines(o);
+		DoPlot(o);				o->UpdateRect(&rDims, false);
+		ShowCursor(o);			return;
+		}
+	else if(cur_pos.y < (nlines-1)){
+		cur_pos.y++;			cur_pos.x = 0;
+		DelChar(o);				return;
+		}
+}
+
+void
+TextFrame::ReplMark(anyOutput *o, char *ntext)
+{
+	int i, j;
+
+	if(!has_m1 || !has_m2 || !o || !ntext) return;
+	lines2text();
+	Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+	for(i = cpos = 0; i < nlines && i < m1_cpos.y; i++) {
+		if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+		}
+	if(m1_cpos.x)add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], m1_cpos.x);
+	add_to_buff((char**)&text, &cpos, &csize, ntext, 0);			j = cpos;
+	if(m1_cpos.y == m2_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
+	for( ; i < nlines && i < m2_cpos.y; i++);
+	if(i == m2_cpos.y && m2_cpos.y > m1_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
+	for(i++; i < nlines; i++) {
+		if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+		}
+	if(tm_rec)free(tm_rec);			tm_rec = 0L;		has_m1 = has_m2 = false;
+	if(text[j]) {
+		c_char = text[j];						text[j] = 0x01;
+		}
+	else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
+		c_char = lines[i+1][0];					lines[i+1][0] = 0x01;
+		}
+	else if(j == cpos){
+		c_char = 0;		text[cpos++] = 0x01;		text[cpos] = 0;
+		}
+	else cur_pos.x = cur_pos.y = 0;
+	text2lines(o);		DoPlot(o);	o->UpdateRect(&rDims, false);
+	ShowCursor(o);
+}
+
+void
+TextFrame::procTokens()
+{
+	int i, j;
+
+	for(i = 0; i < nlines; i++) {
+		if(lines[i] && lines[i][0]){
+			for(j = 0; lines[i][j]; j++) switch(lines[i][j]) {
+				case 0x01:
+					cur_pos.y = i;				cur_pos.x = j;
+					lines[i][j] = c_char;		c_char = '?';
+					break;
+				case 0x02:
+					m1_pos.y = i;				m1_pos.x = j;
+					if(m1_char == 0x01) {
+						lines[i][j] = c_char;	c_char = '?';
+						cur_pos.y = i;			cur_pos.x = j;
+						}
+					else lines[i][j] = m1_char;
+					has_m1 = true;				m1_char = '?';
+					break;
+				case 0x03:
+					m2_pos.y = i;				m2_pos.x = j;
+					if(m2_char == 0x01) {
+						lines[i][j] = c_char;	c_char = '?';
+						cur_pos.y = i;			cur_pos.x = j;
+						}
+					else lines[i][j] = m2_char;
+					has_m2 = true;				m2_char = '?';
+					break;
+					}
+			}
+		}
+}
+
+bool
+TextFrame::DoPaste(anyOutput *o)
+{
+	int i, j, k;
+	char *ntxt;
+	unsigned char *ptxt;
+
+	if((ptxt = PasteText()) && ptxt[0]) {
+		lines2text();	Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+		if(!(ntxt = (char*)malloc(strlen((char*)ptxt)+1))) return false;
+		for(i = j = cpos = 0; ptxt[i]; i++) {
+			if(ptxt[i] >= ' ' || ptxt[i] == '\n') ntxt[j++] = ptxt[i];
+			else if(ptxt[i] == 9)ntxt[j++] = ' ';		//convert tab->space 
+			}
+		ntxt[j] = 0;
+		if(!ntxt[0]) {
+			free(ntxt);				return false;
+			}
+		if(has_m1 && has_m2) {
+			ReplMark(o, ntxt);		free(ntxt);
+			return true;
+			}
+		m1_char = ntxt[0];			ntxt[0] = 0x02;
+		ntxt[j] = 0;				if(text) free(text);
+		if(!(text = (unsigned char*)malloc(csize = 1000)))return false;
+		for(i = k = 0, text[0] = 0; i < nlines; i++) {
+			if(lines[i] && lines[i][0]){
+				if(i == cur_pos.y) {
+					if(cur_pos.x) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], cur_pos.x);
+					add_to_buff((char**)&text, &cpos, &csize, ntxt, 0);	k = cpos;
+					add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i]+cur_pos.x, 0);
+					free(ntxt);		ntxt = 0L;
+					}
+				else add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+				}
+			}
+		if(ntxt) {
+			add_to_buff((char**)&text, &cpos, &csize, ntxt, 0);			k = cpos;
+			}
+		m2_char = 0x01;
+		if(text[k]) {
+			c_char = text[k];						text[k] = 0x03;
+			}
+		else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
+			c_char = lines[i+1][0];					lines[i+1][0] = 0x03;
+			}
+		else if(k == cpos){
+			c_char = 0;		text[cpos++] = 0x03;	text[cpos] = 0;
+			}
+		text2lines(o);						DoPlot(o);
+		o->UpdateRect(&rDims, false);
+		ShowCursor(o);						if(ntxt) free(ntxt);
+		}
+	return false;
+}
+void
+TextFrame::TextMark(anyOutput *o, int mode)
+{
+	int i, j, w, h;
+	LineDEF ld;
+	FillDEF fd;
+
+	if(m1_pos.y > m2_pos.y) {
+		m1_cpos.y = m2_pos.y;				m1_cpos.x = m2_pos.x;
+		m2_cpos.y = m1_pos.y;				m2_cpos.x = m1_pos.x;
+		}
+	else if(m1_pos.y == m2_pos.y  && m1_pos.x > m2_pos.x) {
+		m1_cpos.x = m2_pos.x;				m2_cpos.x = m1_pos.x;
+		m1_cpos.y = m2_cpos.y = m1_pos.y;
+		}
+	else {
+		m1_cpos.y = m1_pos.y;				m1_cpos.x = m1_pos.x;
+		m2_cpos.y = m2_pos.y;				m2_cpos.x = m2_pos.x;
+		}
+	if(!has_m1 || !has_m2 || !o) return;
+	if(m1_pos.y == m2_pos.y && m1_pos.x == m2_pos.x) return;
+	if(mode == 1){							//create background mark
+		if(tm_rec)free(tm_rec);				tm_rec = 0L;
+		if((tm_c = m2_cpos.y - m1_cpos.y +1)<1) return;
+		if(!(tm_rec = (RECT*)malloc(tm_c * sizeof(RECT))))return;
+		for(i = w = 0, j = m1_cpos.y; j <= m2_cpos.y; i++, j++) {
+			h = TextDef.iSize;
+			if(j == m1_cpos.y) {
+				fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+				if(m1_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m1_cpos.x);
+				else w = 0;
+				tm_rec[0].left = w + rDims.left + ipad.left + 1;			
+				fmt_txt.SetText(0L, (char*)(lines[j]+m1_cpos.x), 0L, 0L);
+				fmt_txt.oGetTextExtent(o, &w, &h, 0);
+				tm_rec[0].right = tm_rec[0].left + w;
+				}
+			if(j == m2_cpos.y) {
+				fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+				if(m2_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m2_cpos.x);
+				else w = 0;
+				tm_rec[i].right = w + rDims.left + ipad.left - 1;			
+				if(m2_cpos.y > m1_cpos.y) {
+					tm_rec[i].left = rDims.left + ipad.left;
+					}
+				}
+			else if(j < m2_cpos.y && j > m1_cpos.y) {
+				tm_rec[i].left = rDims.left + ipad.left;
+				tm_rec[i].top = j * linc + rDims.top + ipad.top;
+				fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+				fmt_txt.oGetTextExtent(o, &w, &h, 0);
+				tm_rec[i].right = w + rDims.left + ipad.left;			
+				}
+			tm_rec[i].top = j * linc + rDims.top + ipad.top;
+			tm_rec[i].bottom = tm_rec[i].top + linc;
+			}
+		ld.color = 0x0000ffff;				ld.patlength = 1.0;
+		ld.pattern = 0x0L;					ld.width = 0;
+		fd.color = fd.color2 = ld.color;	fd.hatch = 0L;
+		fd.scale = 1.0;						fd.type = 0;
+		o->SetLine(&ld);					o->SetFill(&fd);
+		for(i = 0; i < tm_c; i++) {
+			o->oRectangle(tm_rec[i].left, tm_rec[i].top, tm_rec[i].right, tm_rec[i].bottom, 0L);
+			}
+		}
+	if(mode == 2){							//invert rectangles
+		if(tm_rec) for(i = 0; i < tm_c; i++) {
+			o->CopyBitmap(tm_rec[i].left, tm_rec[i].top, o, tm_rec[i].left, tm_rec[i].top,
+				tm_rec[i].right - tm_rec[i].left, tm_rec[i].bottom - tm_rec[i].top, true);
+			}
+		}
+	if(mode == 3){							//clear mark
+		if(tm_rec)free(tm_rec);			tm_rec = 0L;
+		tm_c = 0;						has_m1 = has_m2 = false;
+		DoPlot(o);						o->UpdateRect(&rDims, false);
+		}
+}
+
+bool
+TextFrame::CopyText(anyOutput *o, bool b_cut)
+{
+	int i, csize, pos = 0;
+	char *ntxt;
+
+	if(!lines || !lines[0][0] || !o) return false;
+	if(!has_m1 || !has_m2) {
+		m1_pos.x = m1_pos.y = 0;		m2_pos.y = nlines-1;
+		if(lines[nlines-1]) m2_pos.x = (int)strlen((char*)lines[nlines-1]);
+		else m2_pos.x = 0;				has_m1 = has_m2 = true;
+		DoPlot(o);						o->UpdateRect(&rDims, false);
+		return CopyText(o, false);
+		}
+	if(!(ntxt = (char*)malloc(csize = 1000))) return false;
+	if(m1_cpos.y == m2_cpos.y) {
+		add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, m2_cpos.x - m1_cpos.x);
+		::CopyText(ntxt, pos);			free(ntxt);
+		}
+	else if(m1_cpos.y < m2_cpos.y){
+		add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, 0);
+		for(i = m1_cpos.y; i < m2_cpos.y; i++) {
+			add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), 0);
+			}
+		add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), m2_pos.x);
+		::CopyText(ntxt, pos);			free(ntxt);
+		}
+	else {
+		free(ntxt);						return false;
+		}
+	if(b_cut) ReplMark(o, "");
+	return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The segment object is either a pie slice or a ring segment
+//
+segment::segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2,
+				 double a1, double a2):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	segFill.hatch = &segFillLine;
+	segFill.color = 0x00c0c0c0L;
+	fCent.fx = c->fx;		fCent.fy = c->fy;
+	radius1 = r1;			radius2 = r2;
+	angle1 = a1;			angle2 = a2;
+	Id = GO_SEGMENT;
+	bModified = false;
+}
+
+segment::segment(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+segment::~segment()
+{
+	if(pts && nPts) free(pts);
+	if(bModified) Undo.InvalidGO(this);
+}
+	
+bool 
+segment::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_XPOS:		fCent.fx = value;		break;
+	case SIZE_YPOS:		fCent.fy = value;		break;
+	case SIZE_RADIUS1:	radius1 = value;		break;
+	case SIZE_RADIUS2:	radius2 = value;		break;
+	case SIZE_ANGLE1:	angle1 = value;			break;
+	case SIZE_ANGLE2:	angle2 = value;			break;
+	default:			return false;
+		}
+	return true;
+}
+
+void
+segment::DoPlot(anyOutput *o)
+{
+	double dsize, dpt, frx1, frx2, dtmp, da, dda, sia, csia;
+	int i, n, npt = 12;
+	POINT np, of, cp,  *tmppts;
+
+	if(!o || angle1 == angle2) return;
+	dsize = angle1 > angle2 ? angle1 -angle2 : (angle1+360.0)-angle2;
+	dpt = dsize*0.01745329252;		//degrees to rad
+	frx1 = (double)o->un2fix(radius1);
+	frx2 = (double)o->un2fix(radius2);
+	dtmp = frx1*dpt;
+	npt += (int)(dtmp < dsize ? dtmp : dsize);
+	dtmp = frx2*dpt;
+	npt += (int)(dtmp < dsize ? dtmp : dsize);
+	if(!(pts = (POINT*)malloc(npt*sizeof(POINT))))return;
+	nPts = 0;
+	n = (dtmp < dsize) ? (int)dtmp : (int)dsize;
+	while (n<2) n++;
+	da = angle1*0.01745329252;
+	dda = (dsize*0.01745329252)/(double)n;
+	sia = sin(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
+	csia = cos(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
+	of.x = o->un2ix(shift * csia);
+	of.y = - (o->un2iy(shift * sia));
+	cp.x = o->co2ix(fCent.fx + (parent ? parent->GetSize(SIZE_GRECT_LEFT): 0.0));
+	cp.y = o->co2iy(fCent.fy + (parent ? parent->GetSize(SIZE_GRECT_TOP): 0.0));
+	for(i = 0; i < n; i++) {
+		sia = sin(da);					csia = cos(da);
+		np.x = of.x + cp.x;				np.y = of.y + cp.y;
+		np.x += o->un2ix(csia*radius2);	np.y -= o->un2iy(sia*radius2);
+		AddToPolygon(&nPts, pts, &np);
+		da -= dda;
+		}
+	sia = sin(angle2 *0.01745329252);
+	csia = cos(angle2 *0.01745329252);
+	np.x = of.x + cp.x;					np.y = of.y + cp.y;
+	np.x += o->un2ix(csia*radius2);		np.y -= o->un2iy(sia*radius2);
+	AddToPolygon(&nPts, pts, &np);
+	dtmp = frx1*dpt;
+	n = dtmp < dsize ? (int)dtmp : (int)dsize;
+	da = angle2*0.01745329252;
+	if(n>1)dda = (dsize*0.01745329252)/(double)n;
+	else dda = 0.0;
+	for(i = 0; i < n; i++) {
+		sia = sin(da);					csia = cos(da);
+		np.x = of.x + cp.x;				np.y = of.y + cp.y;
+		np.x += o->un2ix(csia*radius1);	np.y -= o->un2iy(sia*radius1);
+		AddToPolygon(&nPts, pts, &np);
+		da += dda;
+		}
+	sia = sin(angle1 *0.01745329252);	csia = cos(angle1 *0.01745329252);
+	np.x = of.x + cp.x;					np.y = of.y + cp.y;
+	np.x += o->un2ix(csia*radius1);		np.y -= o->un2iy(sia*radius1);
+	AddToPolygon(&nPts, pts, &np);
+	if(nPts <3) return;
+	AddToPolygon(&nPts, pts, &pts[0]);	//close polygon
+	o->SetLine(&segLine);				o->SetFill(&segFill);
+	o->oPolygon(pts, nPts);
+	if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+	i = 3*o->un2ix(segLine.width);		//increase size of rectangle for marks
+	IncrementMinMaxRect(&rDims, i+6);
+}
+
+void
+segment::DoMark(anyOutput *o, bool mark)
+{
+	if(mark)InvertPolygon(pts, nPts, &segLine, &segFill, &rDims, o, mark);
+	else if(parent) {
+		parent->DoPlot(o);
+		o->UpdateRect(&rDims, false);
+		}
+}
+
+bool
+segment::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	FillDEF *TmpFill;
+	LegItem *leg;
+
+	switch (cmd) {
+	case CMD_SCALE:
+		fCent.fx *= ((scaleINFO*)tmpl)->sx.fy;			fCent.fy *= ((scaleINFO*)tmpl)->sx.fy;
+		radius1 *= ((scaleINFO*)tmpl)->sx.fy;			radius2 *= ((scaleINFO*)tmpl)->sx.fy;
+		segLine.width *= ((scaleINFO*)tmpl)->sx.fy;		segLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
+		segFillLine.width *= ((scaleINFO*)tmpl)->sx.fy;	segFillLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
+		segFill.scale *= ((scaleINFO*)tmpl)->sx.fy;		shift *= ((scaleINFO*)tmpl)->sx.fy;
+		return true;
+	case CMD_LEGEND:
+		if(tmpl) {
+			leg = new LegItem(this, data, 0L, &segLine, &segFill, 0L);
+			if(!((Legend*)tmpl)->Command(CMD_DROP_OBJECT, leg, o)) DeleteGO(leg);
+			}
+		return true;
+	case CMD_MOUSE_EVENT:
+		switch (((MouseEvent*)tmpl)->Action) {
+		case MOUSE_LBUP:
+			if(ObjThere(((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) 
+				return o->ShowMark(CurrGO=this, MRK_GODRAW);
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_SEGMENT;
+		return true;
 	case CMD_REDRAW:
-		if(is3D && o) {
-			DoPlotText(o);
-			is3D = false;										//enable edit
-			}
-		else if(CurrGO == this) {
-			if(parent && parent->parent) RedrawEdit(defDisp);	//not a dialog
-			else ShowCursor(defDisp);							//dialog !
-			}
-		else return parent->Command(cmd, tmpl, o);
-		return true;
-	case CMD_MOVE:
-		if(parent && (parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM))
-			return parent->Command(cmd, tmpl, o);
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		if(fmt_txt) delete(fmt_txt);	fmt_txt = 0L;
-		if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
-		if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
-		if(o){
-			o->StartPage();		parent->DoPlot(o);		o->EndPage();
-			}
-		return bModified = true;
-		}
-	return false;
-}
-
-void *
-Label::ObjThere(int x, int y)
-{
-	POINT p1;
-
-	if(IsInRect(&rDims, p1.x = x, p1.y = y) && IsInPolygon(&p1, pts, 5))
-		return this;
-	return 0L;
-}
-
-void
-Label::Track(POINT *p, anyOutput *o)
-{
-	POINT *tpts;
-	RECT old_rc;
-	int i;
-
-	if(!parent) return;
-	if(parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM){
-		parent->Track(p, o);
-		return;
-		}
-	if(o && (tpts = (POINT*)malloc(5*sizeof(POINT)))){
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		//note: mLabel set Id to zero upon trackking
-		//   thus rectangle is not updated if parent is a mLabel
-		if(parent->Id) o->UpdateRect(&rDims, false);
-		for(i = 0; i < 5; i++) {
-			tpts[i].x = pts[i].x+p->x;	tpts[i].y = pts[i].y+p->y;
-			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
-			}
-		o->ShowLine(tpts, 5, TextDef.ColTxt);
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		free(tpts);
-		}
-}
-
-bool
-Label::CalcRect(anyOutput *o)
-{
-	int rx1, rx, ry;
-	fRECT rc, rcc;
-
-	if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
-	if(fmt_txt && TextDef.text && TextDef.text[0]) {
-		fmt_txt->SetText(0L, TextDef.text, &ix, &iy);
-		if(!(fmt_txt->oGetTextExtent(o, &rx, &ry, 0))) return false;
-		rx++;
-		}
-	else {
-		if(!(o->oGetTextExtent("A", 1, &rx, &ry))) return false;
-		rx = 1;
-		}
-	rx += 4;	rc.Xmin = -2.0f;	rc.Ymin = 0.0f;		rc.Xmax = rx;		rc.Ymax = ry;
-	si = sin(TextDef.RotBL *0.01745329252);	csi = cos(TextDef.RotBL *0.01745329252);
-	if(TextDef.Align & TXA_HCENTER) {
-		rc.Xmin -= rx/2.0-1.0;		rc.Xmax -= rx/2.0-1.0;
-		}
-	else if(TextDef.Align & TXA_HRIGHT) {
-		rc.Xmin -= rx-2.0;			rc.Xmax -= rx-2.0;
-		}
-	if(TextDef.Align & TXA_VCENTER) {
-		rc.Ymin -= ry/2.0;			rc.Ymax -= ry/2.0;
-		}
-	else if(TextDef.Align & TXA_VBOTTOM) {
-		rc.Ymin -= ry;				rc.Ymax -= ry;
-		}
-	if(fmt_txt && fmt_txt->oGetTextExtent(o, &rx1, &ry, CursorPos)){
-		rx = CursorPos ? (int)rx1 : 0;
-		}
-	else rx = 0;
-	rcc.Xmax = rc.Xmin + (double)rx+2.0;	rcc.Ymin = rc.Ymin+2.0;
-	rcc.Xmin = rc.Xmin;						rcc.Ymax = rc.Ymax-2.0;
-	pts[0].x = iround(rc.Xmin*csi + rc.Ymin*si)+ix;
-	pts[0].y = iround(rc.Ymin*csi - rc.Xmin*si)+iy;
-	pts[1].x = iround(rc.Xmax*csi + rc.Ymin*si)+ix;
-	pts[1].y = iround(rc.Ymin*csi - rc.Xmax*si)+iy;
-	pts[2].x = iround(rc.Xmax*csi + rc.Ymax*si)+ix;
-	pts[2].y = iround(rc.Ymax*csi - rc.Xmax*si)+iy;
-	pts[3].x = iround(rc.Xmin*csi + rc.Ymax*si)+ix;
-	pts[3].y = iround(rc.Ymax*csi - rc.Xmin*si)+iy;
-	pts[4].x = pts[0].x;	pts[4].y = pts[0].y;
-	Cursor.left = iround(rcc.Xmax*csi + rcc.Ymin*si)+ix;
-	Cursor.top = iround(rcc.Ymin*csi - rcc.Xmax*si)+iy;
-	Cursor.right = iround(rcc.Xmax*csi + rcc.Ymax*si)+ix;
-	Cursor.bottom = iround(rcc.Ymax*csi - rcc.Xmax*si)+iy;
-	return true;
-}
-
-void 
-Label::RedrawEdit(anyOutput *o)
-{
-	FillDEF bgFill = {FILL_NONE, bgcolor, 1.0, 0L, bgcolor};
-
-	if(!o || !parent) return;
-	bgLine.color = bgcolor;		o->SetLine(&bgLine);	o->SetFill(&bgFill);
-	o->oPolygon(pts, 5);		IncrementMinMaxRect(&rDims, 3);		
-	o->UpdateRect(&rDims, false);
-	CalcRect(o);				bgLine.color ^= 0x00ffffffL;
-	o->SetLine(&bgLine);		o->oPolygon(pts, 5);
-	if(parent->Id == GO_MLABEL) {
-		if(parent->parent && parent->parent->Id == GO_LEGITEM && parent->parent->parent)
-			parent->parent->parent->DoPlot(o);
-		else parent->DoPlot(o);
-		}
-	else if(parent->Id == GO_LEGITEM && parent->parent) parent->parent->DoPlot(o);
-	else DoPlot(o);
-	o->UpdateRect(&rDims, false);
-	DoMark(o, true);			ShowCursor(o);
-}
-
-void
-Label::SetModified()
-{
-	AxisDEF *adef;
-
-	bModified = true;
-	if(parent && parent->Id==GO_TICK && parent->parent && parent->parent->Id==GO_AXIS){
-	adef = ((Axis*)(parent->parent))->GetAxis();
-	adef->flags &= ~AXIS_AUTOSCALE;
-	}
-}
+		return parent ? parent->Command(cmd, tmpl, o) : false;
+	case CMD_SEG_FILL:
+		TmpFill = (FillDEF *)tmpl;
+		if(TmpFill) {
+			segFill.type = TmpFill->type;			segFill.color = TmpFill->color;
+			segFill.scale = TmpFill->scale;
+			if(TmpFill->hatch) memcpy(&segFillLine, TmpFill->hatch, sizeof(LineDEF));
+			}
+		return true;
+	case CMD_SEG_LINE:
+		if(tmpl) memcpy(&segLine, tmpl, sizeof(LineDEF));
+		return true;
+	case CMD_SEG_MOVEABLE:
+		if(tmpl) moveable = *((int*)tmpl);
+		return true;
+	case CMD_SHIFT_OUT:
+		if(tmpl) shift = *((double*)tmpl);
+		return true;
+	case CMD_MOVE:
+		bModified = true;
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		fCent.fx += ((lfPOINT*)tmpl)[0].fx;		fCent.fy += ((lfPOINT*)tmpl)[0].fy;
+		if(parent)parent->Command(CMD_REDRAW, 0L, o);
+		return true;
+		}
+	return false;
+}
+
+void *
+segment::ObjThere(int x, int y)
+{
+	bool bFound = false;
+	POINT p1;
+
+	if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
+		bFound = IsInPolygon(&p1, pts, nPts);
+		if(bFound || IsCloseToPL(p1, pts, nPts)) return this;
+		}
+	return 0L;
+}
+
+void
+segment::Track(POINT *p, anyOutput *o)
+{
+	POINT *tpts;
+	RECT old_rc;
+	int i;
+
+	if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		for(i = 0; i < nPts; i++) {
+			tpts[i].x = pts[i].x+p->x;			tpts[i].y = pts[i].y+p->y;
+			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+			}
+		o->ShowLine(tpts, nPts, segLine.color);
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		free(tpts);
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the polyline object
+//
+polyline::polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
+	GraphObj(par, d)
+{
+	double dx = 0.0, dy = 0.0;
+	int i;
+
+	FileIO(INIT_VARS);
+	if(parent){
+		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+		}
+	if(cpts && (Values = (lfPOINT*)malloc((nPoints = cpts)* sizeof(lfPOINT)))){
+		memcpy(Values, fpts, cpts*sizeof(lfPOINT));
+		for(i = 0; i < cpts; i++) {
+			Values[i].fx -= dx;		Values[i].fy -= dy;
+			}
+		}
+	Id = GO_POLYLINE;
+	bModified = false;
+}
+
+polyline::polyline(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	bModified = false;
+}
+
+polyline::~polyline()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+	if(this == CurrGO) CurrGO = 0L;
+	if(bModified) Undo.InvalidGO(this);
+}
+
+double
+polyline::GetSize(int select)
+{
+	int i;
+
+	if(select >= SIZE_XPOS && select <=  SIZE_XPOS_LAST){
+		if((i = select-SIZE_XPOS) >=0 && i <= 200)
+			return i < nPoints ? Values[i].fx : Values[nPoints-2].fx;
+		}
+	if(select >= SIZE_YPOS && select <= SIZE_YPOS_LAST){
+		if((i = select-SIZE_YPOS) >=0 && i <= 200)
+			return i < nPoints ? Values[i].fy : Values[nPoints-2].fy;
+		}
+	return parent ? parent->GetSize(select) : 0.0;
+}
+
+DWORD
+polyline::GetColor(int select)
+{
+	return pgLine.color;
+}
+
+bool
+polyline::SetSize(int select, double value)
+{
+	int i;
+
+	if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <=  SIZE_XPOS_LAST){
+		if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)nPoints){
+			Values[i].fx = value;
+			return true;
+			}
+		}
+	if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
+		if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)nPoints){
+			Values[i].fy = value;
+			return true;
+			}
+		}
+	return false;
+}
+
+void
+polyline::DoPlot(anyOutput *o)
+{
+	POINT np, *tmppts;
+	double dx, dy;
+	int i;
+
+	if(!Values || !nPoints || !o || !parent) return;
+	if(pts) free(pts);
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	if(!(pts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
+	for(i = nPts = 0; i < nPoints; i++){
+		np.x = o->co2ix(Values[i].fx + dx);		np.y = o->co2iy(Values[i].fy + dy);
+		AddToPolygon(&nPts, pts, &np);
+		}
+	if(type == 1) AddToPolygon(&nPts, pts, &pts[0]);	//close polygon
+	if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
+	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+	for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+	i = 3*o->un2ix(pgLine.width)+3;		//increase size of rectangle for marks
+	IncrementMinMaxRect(&rDims, i);
+	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+	else switch(type) {
+	case 0:				//line
+		o->SetLine(&pgLine);							o->oPolyline(pts, nPts);
+		break;
+	case 1:				//polygon
+		o->SetLine(&pgLine);	o->SetFill(&pgFill);	o->oPolygon(pts, nPts);
+		break;
+		}
+}
+
+void
+polyline::DoMark(anyOutput *o, bool mark)
+{
+	RECT upd;
+
+	memcpy(&upd, &rDims, sizeof(RECT));
+	IncrementMinMaxRect(&upd, 6 + o->un2ix(pgLine.width)*4);
+	if(mark) {
+		o->SetLine(&pgLine);
+		if(nPoints < 200){
+			switch(type) {
+			case 0:				//line
+				o->oPolyline(pts, nPts);
+			break;
+			case 1:				//polygon
+				o->SetFill(&pgFill);		o->oPolygon(pts, nPts);
+				break;
+				}
+			ShowPoints(o);
+			}
+		else InvertLine(pts, nPts, &pgLine, &upd, o, true);;
+		o->UpdateRect(&upd, false);
+ 		}
+	else {
+		if(parent)	parent->DoPlot(o);
+		}
+}
+
+bool
+polyline::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	POINT p1;
+	bool bFound = false;
+	int i;
+
+	switch (cmd) {
+	case CMD_MRK_DIRTY:			//issued by Undo
+		CurrGO = this;
+		bModified = true;
+	case CMD_FLUSH:
+		if(pHandles) {
+			for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
+			free(pHandles);		pHandles = 0L;
+			}
+		if(cmd == CMD_FLUSH && Values && nPoints){
+			free(Values);
+			Values = 0L;	nPoints = 0;
+			}
+		if(pts && nPts) free(pts);		pts = 0L;		nPts = 0;
+		return true;
+	case CMD_SCALE:
+		if(Values) for(i = 0; i < nPoints; i++){
+			Values[i].fx = ((scaleINFO*)tmpl)->sx.fx + Values[i].fx * ((scaleINFO*)tmpl)->sx.fy;
+			Values[i].fy = ((scaleINFO*)tmpl)->sy.fx + Values[i].fy * ((scaleINFO*)tmpl)->sy.fy;
+			}
+		pgLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;		pgLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;	pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(!ObjThere(p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPoints <2)return false;
+			return o->ShowMark(CurrGO=this, MRK_GODRAW);
+			}
+		return false;
+	case CMD_DELOBJ:
+		if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
+			for(i = 0; i < nPoints; i++) if(pHandles[i] == CurrHandle) {
+				Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
+				for( ; i < nPoints-1; i++) {
+					Values[i].fx = Values[i+1].fx;	Values[i].fy = Values[i+1].fy;
+					}
+				nPoints--;
+				if(pHandles[nPoints])delete(pHandles[nPoints]);
+				pHandles[nPoints] = 0L;				CurrHandle = 0L;
+				CurrGO = this;						bModified = true;
+				return true;
+				}
+			}
+		return false;
+	case CMD_SAVEPOS:
+		if(tmpl && Values) {
+			bModified = true;
+			i = *(int*)tmpl;
+			if(i >= 0 && i < nPoints) Undo.SaveLFP(this, Values + i, 0L);
+			}
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = type == 1 ? GO_POLYGON : GO_POLYLINE;
+		return true;
+	case CMD_SETSCROLL:		case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		return false;
+	case CMD_MOVE:
+		bModified = true;
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		for(i = 0; i < nPoints; i++) {
+			Values[i].fx += ((lfPOINT*)tmpl)[0].fx;
+			Values[i].fy += ((lfPOINT*)tmpl)[0].fy;
+			}
+		if(o) {
+			o->StartPage();		parent->DoPlot(o);		o->EndPage();
+			}
+		return true;
+		}
+	return false;
+}
 
-void
-Label::DoPlotText(anyOutput *o)
+void * 
+polyline::ObjThere(int x, int y)
 {
-	if(!parent || !o) return;
-	defDisp = o;
-	if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
-	switch(flags & 0x03) {
-	case LB_X_DATA:	ix = o->fx2ix(fPos.fx);		break;
-	case LB_X_PARENT: 
-		ix = iround(parent->GetSize(SIZE_LB_XPOS));
-		break;
-	default:
-		ix = o->co2ix(fPos.fx + parent->GetSize(SIZE_GRECT_LEFT));
-		break;
-		}
-	switch(flags & 0x30) {
-	case LB_Y_DATA:	iy = o->fy2iy(fPos.fy);		break;
-	case LB_Y_PARENT: 
-		iy = iround(parent->GetSize(SIZE_LB_YPOS));
-		break;
-	default:
-		iy = o->co2iy(fPos.fy +parent->GetSize(SIZE_GRECT_TOP));
-		break;
-		}
-	ix += o->un2ix(fDist.fx);		iy += o->un2iy(fDist.fy);
-	TextDef.iSize = o->un2iy(TextDef.fSize);
-	o->SetTextSpec(&TextDef);
-	if(TextDef.text && TextDef.text[0]){
-		if(fmt_txt) fmt_txt->SetText(o, TextDef.text, &ix, &iy);
-		else fmt_txt = new fmtText(o, ix, iy, TextDef.text);
+	bool bFound = false;
+	POINT p1;
+	int i;
+	void *ret;
+
+	if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
+		if(CurrGO == this && pHandles) for(i = nPoints-1; i >= 0; i--) 
+			if((pHandles[i]) && (ret = pHandles[i]->ObjThere(x, y))) return ret;
+		if(type == 1) bFound = IsInPolygon(&p1, pts, nPts);
+		if(bFound || IsCloseToPL(p1,pts,nPts)) return this;
 		}
-	if(!(CalcRect(o))) return;
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
-	UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+	return 0L;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// a multiline label consists of several Label objects
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt, 
-	int cp, DWORD flg):GraphObj(par, d)
-{
-	int i;
-
-	memcpy(&TextDef, td, sizeof(TextDEF));
-	TextDef.text = 0L;		fPos.fx = x;		fPos.fy = y;
-	Lines = 0L;				flags = flg;		lspc = 1.0;
-	fDist.fx = 0.0;			fDist.fy = 0.0;
-	CurrGO = CurrLabel = 0L;
-	if(txt && (Lines = (Label**)calloc(2, sizeof(Label*)))) {
-		for(i = 0; i < cp && txt[i]; i ++) TmpTxt[i] = txt[i];
-		TmpTxt[i] = 0;
-		if(Lines[0] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT))
-			Lines[0]->Command(CMD_SETTEXT, TmpTxt, 0L);
-		if(Lines[1] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
-			Lines[1]->Command(CMD_SETTEXT, txt+cp, 0L);
-			CurrGO = CurrLabel = Lines[1];
-			}
-		nLines = 2;		cli = 1;
-		}
-	Id = GO_MLABEL;
-}
-
-mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt)
-	:GraphObj(par, d)
-{
-	int i, nll;
-	char **llist;
-
-	memcpy(&TextDef, td, sizeof(TextDEF));
-	TextDef.text = 0L;		fPos.fx = x;		fPos.fy = y;
-	Lines = 0L;				flags = 0L;			Id = GO_MLABEL;
-	fDist.fx = 0.0;			fDist.fy = 0.0;		lspc = 1.0;
-	CurrGO = CurrLabel = 0L;
-	if(txt){
-		if((llist=split(txt,'\n',&nll)) && nll && (Lines=(Label**)calloc(nll, sizeof(Label*)))){
-			for(i = 0; i < nll; i++) {
-				if(llist[i]){
-					Lines[i] = new 	Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT);
-					Lines[i]->Command(CMD_SETTEXT, llist[i], 0L);
-					free(llist[i]);
-					}
-				}
-			free(llist);	nLines = nll;		cli = 0;
-			}
-		}
-}
-
-mLabel::mLabel(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-}
-
-mLabel::~mLabel()
-{
-	int i;
-	
-	Undo.InvalidGO(this);
-	if(Lines){
-		for(i = 0; i < nLines; i++) if(Lines[i]) DeleteGO(Lines[i]);
-		free(Lines);
-		}
-}
-
-double
-mLabel::GetSize(int select)
-{
-	switch(select){
-	case SIZE_LB_XPOS:	return cPos1.fx;
-	case SIZE_LB_YPOS:	return cPos1.fy;
-	case SIZE_GRECT_TOP:	
-		if (parent) return parent->GetSize(select);
-		break;
-	case SIZE_MIN_Z:	case SIZE_MAX_Z:	case SIZE_ZPOS:
-		return curr_z;
-	case SIZE_LSPC:
-		return lspc;
-		}
-	return 0.0;
-}
-
-bool
-mLabel::SetSize(int select, double value)
+
+void
+polyline::Track(POINT *p, anyOutput *o)
 {
+	POINT *tpts;
+	RECT old_rc;
 	int i;
-
-	switch(select & 0xfff) {
-	case SIZE_LB_XDIST:
-		undo_flags = CheckNewFloat(&fDist.fx, fDist.fx, value, this, undo_flags);
-		return true;
-	case SIZE_LB_YDIST:
-		undo_flags = CheckNewFloat(&fDist.fy, fDist.fy, value, this, undo_flags);
-		return true;
-	case SIZE_XPOS:
-		undo_flags = CheckNewFloat(&fPos.fx, fPos.fx, value, this, undo_flags);
-		return true;
-	case SIZE_YPOS:
-		undo_flags = CheckNewFloat(&fPos.fy, fPos.fy, value, this, undo_flags);
-		return true;
-	case SIZE_ZPOS:
-		curr_z = value;
-		if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]){
-			Lines[i]->SetSize(select, value);
+
+	if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		for(i = 0; i < nPts; i++) {
+			tpts[i].x = pts[i].x+p->x;
+			tpts[i].y = pts[i].y+p->y;
+			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
 			}
-		return is3D = true;
-	case SIZE_LSPC:
-		undo_flags = CheckNewFloat(&lspc, lspc, value, this, undo_flags);
-		return true;
-		}
-	return false;
-}
-
-void
-mLabel::DoPlot(anyOutput *o)
-{
-	int i;
-	double dh, dx, dy;
-
-	if(!o || !Lines) return;
-	undo_flags = 0L;
-	if(parent){		//if this object is part of a dialog we dont have a parent
-		dx = parent->GetSize(SIZE_GRECT_LEFT);
-		dy = parent->GetSize(SIZE_GRECT_TOP);
-		}
-	else dx = dy = 0.0;
-	cPos.fx = cPos.fy = 0.0;
-	TextDef.iSize = o->un2iy(TextDef.fSize);
-	switch(flags & 0x03) {
-	case LB_X_DATA:		cPos.fx = o->fx2fix(fPos.fx);				break;
-	case LB_X_PARENT:	if(parent) cPos.fx = parent->GetSize(SIZE_LB_XPOS);	break;
-	default:
-		//if no parent its a dialog
-		cPos.fx = parent ? o->co2fix(fPos.fx + dx) : fPos.fx;
-		break;
-		}
-	switch(flags & 0x30) {
-	case LB_Y_DATA:		cPos.fy = o->fy2fiy(fPos.fy);				break;
-	case LB_Y_PARENT:	if(parent) cPos.fy = parent->GetSize(SIZE_LB_YPOS);	break;
-	default:	
-		//if no parent its a dialog
-		cPos.fy = parent ? o->co2fiy(fPos.fy + dy) : fPos.fy;
-		break;
-		}
-	si = sin(TextDef.RotBL *0.01745329252f);	csi = cos(TextDef.RotBL *0.01745329252f);
-	if(TextDef.Align & TXA_VBOTTOM) dh = (double)(nLines-1);
-	else if(TextDef.Align & TXA_VCENTER) dh = ((double)(nLines-1))/2.0;
-	else dh = 0.0;						dh *= TextDef.fSize;
-	cPos.fx -= o->un2fix(dh*si);		cPos.fy -= o->un2fiy(dh*csi);
-	memcpy(&cPos1, &cPos, sizeof(lfPOINT));
-	if(lspc < 0.5 || lspc > 5) lspc = 1.0;
-	dist.fx = floor(o->un2fix(TextDef.fSize * si * 1.1 * lspc));
-	dist.fy = floor(o->un2fiy(TextDef.fSize * csi * 1.1 * lspc));
-	o->SetTextSpec(&TextDef);
-	rDims.left = rDims.top = rDims.right = rDims.bottom = 0;
-	for(i = 0; i < nLines; i++)	if(Lines[i]){
-		Lines[i]->Command(CMD_SETTEXTDEF, &TextDef, o);
-		Lines[i]->SetSize(SIZE_LB_XDIST, fDist.fx);	Lines[i]->SetSize(SIZE_LB_YDIST, fDist.fy);
-		Lines[i]->SetSize(SIZE_XPOS, fPos.fx);		Lines[i]->SetSize(SIZE_YPOS, fPos.fy);
-		Lines[i]->moveable = moveable;				Lines[i]->DoPlot(o);
-		UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
-		UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
-		}
-	if(CurrLabel && o && Command(CMD_SETFOCUS, CurrLabel, o))
-		Lines[cli]->ShowCursor(o);
-}
-
-bool
-mLabel::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i, j, k;
-	fRECT t_cur;
-	MouseEvent mev;
-
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		if(Lines && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) 
-			for(i = 0; i<nLines; i++) if(Lines[i] && Lines[i]->Command(cmd, tmpl, o)) return true;
-		break;
-	case CMD_HIDE_MARK:
-		if(Lines && o && tmpl) for(i = 0; i< nLines; i++) 
-			if(Lines[i] && tmpl == (void*)Lines[i]){
-				Lines[i]->DoMark(o, false);
-				return true;
-				}
-		return false;
-	case CMD_ADDCHAR:
-		if(!tmpl || 13 != *((int*)tmpl)) return false;
-		if(!Lines[cli] || !Lines[cli]->Command(CMD_GETTEXT, &TmpTxt, o)) return false;
-		k = iround(Lines[cli]->GetSize(SIZE_CURSORPOS));
-		if(parent)Undo.ObjConf(this, 0L);
-		if(tmpl && Lines && (Lines = (Label**)realloc(Lines, (nLines+1) * sizeof(Label*)))) {
-			for(i = nLines-1, j = nLines; i >= cli; i--, j-- ) {
-				Lines[j] = Lines[i];
-				}
-			i++, j++;
-			if(Lines[j]) DeleteGO(Lines[j]);	Lines[i] = Lines[j] = 0L;	nLines++;
-			if(Lines[j] = new 	Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
-				Lines[j]->Command(CMD_SETTEXT, TmpTxt+k, o);
-				Lines[j]->Command(CMD_POS_FIRST, 0L, o);
-				CurrGO = CurrLabel = Lines[j];
-				TmpTxt[k] = 0;
-				}
-			if(Lines[i] = new 	Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT))
-				Lines[i]->Command(CMD_SETTEXT, TmpTxt, 0L);
-			Command(CMD_SETFOCUS, CurrGO, o);
-			if(parent) return parent->Command(CMD_REDRAW, 0L, o);
-			else if(o) DoPlot(o);
-			}
-		break;
-	case CMD_SETFOCUS:
-		for(i = 0; i< nLines; i++) if(Lines[i] == (Label*)tmpl) {
-			cli = i;
-			cPos1.fx = cPos.fx + dist.fx*i;
-			cPos1.fy = cPos.fy + dist.fy*i;
-			return true;
-			}
-		break;
-	case CMD_GETTEXT:
-		if(tmpl && Lines && nLines && Lines[0]) return Lines[0]->Command(CMD_GETTEXT, tmpl, o);
-		break;
-	case CMD_ALLTEXT:
-		if(tmpl && Lines && nLines){
-			for(i = 0, j = 500; i < nLines; i++) {
-				if(Lines[i] && Lines[i]->Command(CMD_GETTEXT, TmpTxt, o) && TmpTxt[0]){
-					j += sprintf(TmpTxt+j, "%s\n", TmpTxt);
-					}
-				}
-			strcpy((char*)tmpl, TmpTxt+500);
-			return true;
-			}
-		break;
-	case CMD_DELETE:
-		cli++;
-		//fall through
-	case CMD_BACKSP:
-		if(cli > 0 && cli < nLines && Lines && Lines[cli] && Lines[cli-1]) {
-			Lines[cli-1]->Command(CMD_POS_LAST, 0L, o);
-			TmpTxt[0] = 0;
-			Lines[cli-1]->Command(CMD_GETTEXT, TmpTxt, o);
-			Lines[cli]->Command(CMD_GETTEXT, TmpTxt+strlen(TmpTxt), o);
-			Lines[cli-1]->Command(CMD_SETTEXT, TmpTxt, o);
-			DeleteGO(Lines[cli]);	Lines[cli] = 0L;
-			for(i = cli+1; i < nLines; i++){
-				Lines[i-1] = Lines[i], Lines[i]= 0L;
-				}
-			nLines--;
-			CurrGO = CurrLabel = Lines[cli-1];
-			if(parent) parent->Command(CMD_REDRAW, 0L, o);
-			if(CurrLabel) CurrLabel->RedrawEdit(o);
-			return true;
-			}
-		return false;
-	case CMD_GETTEXTDEF:
-		if(!tmpl) return false;
-		memcpy(tmpl, &TextDef, sizeof(TextDEF));
-		return true;
-	case CMD_SETTEXTDEF:
-		if(!tmpl)return false;
-		Undo.TextDef(this, &TextDef, undo_flags);
-		undo_flags |= UNDO_CONTINUE;
-		memcpy(&TextDef, tmpl, sizeof(TextDEF));
-		TextDef.text = 0L;
-		return true;
-	case CMD_SET_DATAOBJ:
-		if(Lines) {
-			for(i = 0; i< nLines; i++) if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
-			}
-		Id = GO_MLABEL;
-		data = (DataObj*)tmpl;
-		return true;
-	case CMD_AUTOSCALE:
-		if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
-			&& (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
-			((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
-			return true;
-			}
-		break;
-	case CMD_CURRUP:		case CMD_CURRDOWN:
-		if(!o) return false;
-		o->SetTextSpec(&TextDef);
-		Command(CMD_SETFOCUS, CurrGO, o);
-		if(cli >= 0 && cli < nLines && Lines && Lines[cli]) {
-			t_cur.Xmin = Lines[cli]->GetSize(SIZE_CURSOR_XMIN);
-			t_cur.Xmax = Lines[cli]->GetSize(SIZE_CURSOR_XMAX);
-			t_cur.Ymin = Lines[cli]->GetSize(SIZE_CURSOR_YMIN);
-			t_cur.Ymax = Lines[cli]->GetSize(SIZE_CURSOR_YMAX);
-			mev.StateFlags = 0;		mev.Action = MOUSE_LBUP;
-			mev.x = iround((t_cur.Xmax+t_cur.Xmin)/2.0);
-			mev.y = iround((t_cur.Ymax+t_cur.Ymin)/2.0);
-			i = o->un2ix(TextDef.fSize*si);		j = o->un2iy(TextDef.fSize*csi);
-			if(cmd == CMD_CURRUP && cli > 0 && Lines[cli-1]) {
-				Lines[cli-1]->CalcCursorPos(mev.x -= i, mev.y -= j, o);
-				o->ShowMark(CurrGO = CurrLabel = Lines[cli-=1], MRK_GODRAW);
-				return Command(CMD_SETFOCUS, Lines[cli], o);
-				}
-			if(cmd == CMD_CURRDOWN && cli < (nLines-1) && Lines[cli+1]) {
-				Lines[cli+1]->CalcCursorPos(mev.x += i, mev.y += j, o);
-				o->ShowMark(CurrGO = CurrLabel = Lines[cli+=1], MRK_GODRAW);
-				return Command(CMD_SETFOCUS, Lines[cli], o);
-				}
-			}
-		else return false;
-		break;
-	case CMD_SELECT:
-		if(o && tmpl) for(i = 0; i < nLines; i++){
-			o->SetTextSpec(&TextDef);
-			if(Lines[i] && ((POINT*)tmpl)->y > Lines[i]->rDims.top && ((POINT*)tmpl)->y < 
-				Lines[i]->rDims.bottom) return Lines[i]->Command(cmd, tmpl, o);
-			}
-		break;
-	case CMD_DELOBJ:
-		if(parent && Lines) for(i = 0; i< nLines; i++) 
-			if(Lines[i] && Lines[i] == (Label*)tmpl) return parent->Command(cmd, this, o);
-		break;
-	case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		else if(o) DoPlot(o);
-		break;
-	case CMD_MOVE:
-		if(parent && parent->Id == GO_LEGITEM) return parent->Command(cmd, tmpl, o);
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
-		if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
-		if(o && parent){
-			o->StartPage();		parent->DoPlot(o);		o->EndPage();
-			}
-		return true;
-		}
-	return false;
-}
-
-void
-mLabel::Track(POINT *p, anyOutput *o)
-{
-	int i;
-
-	if(!parent) return;
-	if(parent->Id == GO_LEGITEM){
-		parent->Track(p, o);
-		return;
-		}
-	for(i = 0; i < nLines; i++)	if(Lines[i]){
-		if(!i) memcpy(&rDims, &Lines[i]->rDims, sizeof(RECT));
-		else {
-			UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
-			UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
-			}
-		}
-	o->UpdateRect(&rDims, false);
-	Id = 0L;			//disable reentrance from Label objects
-	for(i = 0; i < nLines; i++)	if(Lines[i]) Lines[i]->Track(p, o);
-	Id = GO_MLABEL;		//enable entrance from Label objects
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The following GOs use absolute coordinates
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The segment object is either a pie slice or a ring segment
-//
-segment::segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2,
-				 double a1, double a2):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	segFill.hatch = &segFillLine;
-	segFill.color = 0x00c0c0c0L;
-	fCent.fx = c->fx;		fCent.fy = c->fy;
-	radius1 = r1;			radius2 = r2;
-	angle1 = a1;			angle2 = a2;
-	Id = GO_SEGMENT;
-	bModified = false;
-}
-
-segment::segment(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-segment::~segment()
-{
-	if(pts && nPts) free(pts);
-	if(bModified) Undo.InvalidGO(this);
-}
-	
-bool 
-segment::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_XPOS:		fCent.fx = value;		break;
-	case SIZE_YPOS:		fCent.fy = value;		break;
-	case SIZE_RADIUS1:	radius1 = value;		break;
-	case SIZE_RADIUS2:	radius2 = value;		break;
-	case SIZE_ANGLE1:	angle1 = value;			break;
-	case SIZE_ANGLE2:	angle2 = value;			break;
-	default:			return false;
-		}
-	return true;
-}
-
-void
-segment::DoPlot(anyOutput *o)
-{
-	double dsize, dpt, frx1, frx2, dtmp, da, dda, sia, csia;
-	int i, n, npt = 12;
-	POINT np, of, cp,  *tmppts;
-
-	if(!o || angle1 == angle2) return;
-	dsize = angle1 > angle2 ? angle1 -angle2 : (angle1+360.0)-angle2;
-	dpt = dsize*0.01745329252;		//degrees to rad
-	frx1 = (double)o->un2fix(radius1);
-	frx2 = (double)o->un2fix(radius2);
-	dtmp = frx1*dpt;
-	npt += (int)(dtmp < dsize ? dtmp : dsize);
-	dtmp = frx2*dpt;
-	npt += (int)(dtmp < dsize ? dtmp : dsize);
-	if(!(pts = (POINT*)malloc(npt*sizeof(POINT))))return;
-	nPts = 0;
-	n = (dtmp < dsize) ? (int)dtmp : (int)dsize;
-	while (n<2) n++;
-	da = angle1*0.01745329252;
-	dda = (dsize*0.01745329252)/(double)n;
-	sia = sin(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
-	csia = cos(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
-	of.x = o->un2ix(shift * csia);
-	of.y = - (o->un2iy(shift * sia));
-	cp.x = o->co2ix(fCent.fx + (parent ? parent->GetSize(SIZE_GRECT_LEFT): 0.0));
-	cp.y = o->co2iy(fCent.fy + (parent ? parent->GetSize(SIZE_GRECT_TOP): 0.0));
-	for(i = 0; i < n; i++) {
-		sia = sin(da);					csia = cos(da);
-		np.x = of.x + cp.x;				np.y = of.y + cp.y;
-		np.x += o->un2ix(csia*radius2);	np.y -= o->un2iy(sia*radius2);
-		AddToPolygon(&nPts, pts, &np);
-		da -= dda;
-		}
-	sia = sin(angle2 *0.01745329252);
-	csia = cos(angle2 *0.01745329252);
-	np.x = of.x + cp.x;					np.y = of.y + cp.y;
-	np.x += o->un2ix(csia*radius2);		np.y -= o->un2iy(sia*radius2);
-	AddToPolygon(&nPts, pts, &np);
-	dtmp = frx1*dpt;
-	n = dtmp < dsize ? (int)dtmp : (int)dsize;
-	da = angle2*0.01745329252;
-	if(n>1)dda = (dsize*0.01745329252)/(double)n;
-	else dda = 0.0;
-	for(i = 0; i < n; i++) {
-		sia = sin(da);					csia = cos(da);
-		np.x = of.x + cp.x;				np.y = of.y + cp.y;
-		np.x += o->un2ix(csia*radius1);	np.y -= o->un2iy(sia*radius1);
-		AddToPolygon(&nPts, pts, &np);
-		da += dda;
-		}
-	sia = sin(angle1 *0.01745329252);	csia = cos(angle1 *0.01745329252);
-	np.x = of.x + cp.x;					np.y = of.y + cp.y;
-	np.x += o->un2ix(csia*radius1);		np.y -= o->un2iy(sia*radius1);
-	AddToPolygon(&nPts, pts, &np);
-	if(nPts <3) return;
-	AddToPolygon(&nPts, pts, &pts[0]);	//close polygon
-	o->SetLine(&segLine);				o->SetFill(&segFill);
-	o->oPolygon(pts, nPts);
-	if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
-	i = 3*o->un2ix(segLine.width);		//increase size of rectangle for marks
-	IncrementMinMaxRect(&rDims, i+6);
-}
-
-void
-segment::DoMark(anyOutput *o, bool mark)
-{
-	if(mark)InvertPolygon(pts, nPts, &segLine, &segFill, &rDims, o, mark);
-	else if(parent) {
-		parent->DoPlot(o);
-		o->UpdateRect(&rDims, false);
-		}
-}
-
-bool
-segment::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	FillDEF *TmpFill;
-	LegItem *leg;
-
-	switch (cmd) {
-	case CMD_LEGEND:
-		if(tmpl) {
-			leg = new LegItem(this, data, 0L, &segLine, &segFill);
-			if(!((Legend*)tmpl)->Command(CMD_DROP_OBJECT, leg, o)) DeleteGO(leg);
-			}
-		return true;
-	case CMD_MOUSE_EVENT:
-		switch (((MouseEvent*)tmpl)->Action) {
-		case MOUSE_LBUP:
-			if(ObjThere(((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) 
-				return o->ShowMark(CurrGO=this, MRK_GODRAW);
-			}
-		return false;
-	case CMD_SET_DATAOBJ:
-		Id = GO_SEGMENT;
-		return true;
-	case CMD_REDRAW:
-		return parent ? parent->Command(cmd, tmpl, o) : false;
-	case CMD_SEG_FILL:
-		TmpFill = (FillDEF *)tmpl;
-		if(TmpFill) {
-			segFill.type = TmpFill->type;			segFill.color = TmpFill->color;
-			segFill.scale = TmpFill->scale;
-			if(TmpFill->hatch) memcpy(&segFillLine, TmpFill->hatch, sizeof(LineDEF));
-			}
-		return true;
-	case CMD_SEG_LINE:
-		if(tmpl) memcpy(&segLine, tmpl, sizeof(LineDEF));
-		return true;
-	case CMD_SEG_MOVEABLE:
-		if(tmpl) moveable = *((int*)tmpl);
-		return true;
-	case CMD_SHIFT_OUT:
-		if(tmpl) shift = *((double*)tmpl);
-		return true;
-	case CMD_MOVE:
-		bModified = true;
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		fCent.fx += ((lfPOINT*)tmpl)[0].fx;		fCent.fy += ((lfPOINT*)tmpl)[0].fy;
-		if(parent)parent->Command(CMD_REDRAW, 0L, o);
-		return true;
-		}
-	return false;
-}
-
-void *
-segment::ObjThere(int x, int y)
-{
-	bool bFound = false;
-	POINT p1;
-
-	if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
-		bFound = IsInPolygon(&p1, pts, nPts);
-		if(bFound || IsCloseToPL(p1, pts, nPts)) return this;
-		}
-	return 0L;
-}
-
-void
-segment::Track(POINT *p, anyOutput *o)
-{
-	POINT *tpts;
-	RECT old_rc;
-	int i;
-
-	if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		o->UpdateRect(&rDims, false);
-		for(i = 0; i < nPts; i++) {
-			tpts[i].x = pts[i].x+p->x;			tpts[i].y = pts[i].y+p->y;
-			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
-			}
-		o->ShowLine(tpts, nPts, segLine.color);
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		free(tpts);
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// the polyline object
-//
-polyline::polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
-	GraphObj(par, d)
-{
-	double dx = 0.0, dy = 0.0;
-	int i;
-
-	FileIO(INIT_VARS);
-	if(parent){
-		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-		}
-	if(cpts && (Values = (lfPOINT*)malloc((nPoints = cpts)* sizeof(lfPOINT)))){
-		memcpy(Values, fpts, cpts*sizeof(lfPOINT));
-		for(i = 0; i < cpts; i++) {
-			Values[i].fx -= dx;		Values[i].fy -= dy;
-			}
-		}
-	Id = GO_POLYLINE;
-	bModified = false;
-}
-
-polyline::polyline(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	bModified = false;
-}
-
-polyline::~polyline()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-	if(this == CurrGO) CurrGO = 0L;
-	if(bModified) Undo.InvalidGO(this);
-}
-
-double
-polyline::GetSize(int select)
-{
-	int i;
-
-	if(select >= SIZE_XPOS && select <=  SIZE_XPOS_LAST){
-		if((i = select-SIZE_XPOS) >=0 && i <= 200)
-			return i < nPoints ? Values[i].fx : Values[nPoints-2].fx;
-		}
-	if(select >= SIZE_YPOS && select <= SIZE_YPOS_LAST){
-		if((i = select-SIZE_YPOS) >=0 && i <= 200)
-			return i < nPoints ? Values[i].fy : Values[nPoints-2].fy;
-		}
-	return parent ? parent->GetSize(select) : 0.0;
-}
-
-DWORD
-polyline::GetColor(int select)
-{
-	return pgLine.color;
-}
-
-bool
-polyline::SetSize(int select, double value)
-{
-	int i;
-
-	if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <=  SIZE_XPOS_LAST){
-		if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)nPoints){
-			Values[i].fx = value;
-			return true;
-			}
-		}
-	if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
-		if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)nPoints){
-			Values[i].fy = value;
-			return true;
-			}
-		}
-	return false;
-}
-
-void
-polyline::DoPlot(anyOutput *o)
-{
-	POINT np, *tmppts;
-	double dx, dy;
-	int i;
-
-	if(!Values || !nPoints || !o || !parent) return;
-	if(pts) free(pts);
-	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-	if(!(pts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
-	for(i = nPts = 0; i < nPoints; i++){
-		np.x = o->co2ix(Values[i].fx + dx);		np.y = o->co2iy(Values[i].fy + dy);
-		AddToPolygon(&nPts, pts, &np);
-		}
-	if(type == 1) AddToPolygon(&nPts, pts, &pts[0]);	//close polygon
-	if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
-	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
-	for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
-	i = 3*o->un2ix(pgLine.width)+3;		//increase size of rectangle for marks
-	IncrementMinMaxRect(&rDims, i);
-	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
-	else switch(type) {
-	case 0:				//line
-		o->SetLine(&pgLine);							o->oPolyline(pts, nPts);
-		break;
-	case 1:				//polygon
-		o->SetLine(&pgLine);	o->SetFill(&pgFill);	o->oPolygon(pts, nPts);
-		break;
-		}
-}
-
-void
-polyline::DoMark(anyOutput *o, bool mark)
-{
-	RECT upd;
-
-	memcpy(&upd, &rDims, sizeof(RECT));
-	IncrementMinMaxRect(&upd, 6 + o->un2ix(pgLine.width)*4);
-	if(mark) {
-		o->SetLine(&pgLine);
-		if(nPoints < 200){
-			switch(type) {
-			case 0:				//line
-				o->oPolyline(pts, nPts);
-			break;
-			case 1:				//polygon
-				o->SetFill(&pgFill);		o->oPolygon(pts, nPts);
-				break;
-				}
-			ShowPoints(o);
-			}
-		else InvertLine(pts, nPts, &pgLine, &upd, o, true);;
-		o->UpdateRect(&upd, false);
- 		}
-	else {
-		if(parent)	parent->DoPlot(o);
-		}
-}
-
-bool
-polyline::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	POINT p1;
-	bool bFound = false;
-	int i;
-
-	switch (cmd) {
-	case CMD_MRK_DIRTY:			//issued by Undo
-		CurrGO = this;
-		bModified = true;
-	case CMD_FLUSH:
-		if(pHandles) {
-			for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
-			free(pHandles);		pHandles = 0L;
-			}
-		if(cmd == CMD_FLUSH && Values && nPoints){
-			free(Values);
-			Values = 0L;	nPoints = 0;
-			}
-		if(pts && nPts) free(pts);		pts = 0L;		nPts = 0;
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(!ObjThere(p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPoints <2)return false;
-			return o->ShowMark(CurrGO=this, MRK_GODRAW);
-			}
-		return false;
-	case CMD_DELOBJ:
-		if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
-			for(i = 0; i < nPoints; i++) if(pHandles[i] == CurrHandle) {
-				Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
-				for( ; i < nPoints-1; i++) {
-					Values[i].fx = Values[i+1].fx;	Values[i].fy = Values[i+1].fy;
-					}
-				nPoints--;
-				if(pHandles[nPoints])delete(pHandles[nPoints]);
-				pHandles[nPoints] = 0L;				CurrHandle = 0L;
-				CurrGO = this;						bModified = true;
-				return true;
-				}
-			}
-		return false;
-	case CMD_SAVEPOS:
-		if(tmpl && Values) {
-			bModified = true;
-			i = *(int*)tmpl;
-			if(i >= 0 && i < nPoints) Undo.SaveLFP(this, Values + i, 0L);
-			}
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = type == 1 ? GO_POLYGON : GO_POLYLINE;
-		return true;
-	case CMD_SETSCROLL:		case CMD_REDRAW:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		return false;
-	case CMD_MOVE:
-		bModified = true;
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		for(i = 0; i < nPoints; i++) {
-			Values[i].fx += ((lfPOINT*)tmpl)[0].fx;
-			Values[i].fy += ((lfPOINT*)tmpl)[0].fy;
-			}
-		if(o) {
-			o->StartPage();		parent->DoPlot(o);		o->EndPage();
-			}
-		return true;
-		}
-	return false;
-}
-
-void * 
-polyline::ObjThere(int x, int y)
-{
-	bool bFound = false;
-	POINT p1;
-	int i;
-	void *ret;
-
-	if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
-		if(CurrGO == this && pHandles) for(i = nPoints-1; i >= 0; i--) 
-			if((pHandles[i]) && (ret = pHandles[i]->ObjThere(x, y))) return ret;
-		if(type == 1) bFound = IsInPolygon(&p1, pts, nPts);
-		if(bFound || IsCloseToPL(p1,pts,nPts)) return this;
-		}
-	return 0L;
-}
-
-void
-polyline::Track(POINT *p, anyOutput *o)
-{
-	POINT *tpts;
-	RECT old_rc;
-	int i;
-
-	if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		o->UpdateRect(&rDims, false);
-		for(i = 0; i < nPts; i++) {
-			tpts[i].x = pts[i].x+p->x;
-			tpts[i].y = pts[i].y+p->y;
-			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
-			}
-		o->ShowLine(tpts, nPts, pgLine.color);
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		free(tpts);
-		}
-}
-
-void
-polyline::ShowPoints(anyOutput *o)
-{
+		o->ShowLine(tpts, nPts, pgLine.color);
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		free(tpts);
+		}
+}
+
+void
+polyline::ShowPoints(anyOutput *o)
+{
 	int i;
 	double dx, dy;
 	POINT hpts[3];
-	LineDEF gl = {0.0, 1.0, 0x00c0c0c0, 0};
-
-	if(nPoints >= 200 || !o) return;
-	if(!pHandles && (pHandles = (dragHandle**)calloc(nPoints+4, sizeof(dragHandle*)))){
-		for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
-		}
+	LineDEF gl = {0.0, 1.0, 0x00c0c0c0, 0};
+
+	if(nPoints >= 200 || !o) return;
+	if(!pHandles && (pHandles = (dragHandle**)calloc(nPoints+4, sizeof(dragHandle*)))){
+		for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
+		}
 	if(!pHandles) return;
 	if(Id == GO_BEZIER && parent && nPoints > 3) {
 		dx = parent->GetSize(SIZE_GRECT_LEFT);			dy = parent->GetSize(SIZE_GRECT_TOP);
@@ -6334,10 +7273,10 @@ polyline::ShowPoints(anyOutput *o)
 		hpts[0].x = o->co2ix(Values[i-1].fx+dx);		hpts[0].y = o->co2iy(Values[i-1].fy+dy);
 		hpts[1].x = o->co2ix(Values[i].fx+dx);			hpts[1].y = o->co2iy(Values[i].fy+dy);
 		o->oPolyline(hpts, 2);
-		}
+		}
 	for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
-}
-
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Beziers are based on the polyline object
 Bezier::Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res):
@@ -6494,24 +7433,26 @@ Bezier::FitCurve(lfPOINT *d, int npt, double error)
 void
 Bezier::RemovePoint(lfPOINT *d, int sel)
 {
-	long o_nPoints;
-	double len;
-	lfPOINT ndata[3], tHat1, tHat2;
+	lfPOINT tHat1, tHat2;
 
-	o_nPoints = nPoints;					nPoints = sel-3;
-	ndata[0].fx = d[sel-3].fx;				ndata[0].fy = d[sel-3].fy;
-	ndata[1].fx = d[sel].fx;				ndata[1].fy = d[sel].fy;
-	ndata[2].fx = d[sel+3].fx;				ndata[2].fy = d[sel+3].fy;
 	tHat1.fx = d[sel-2].fx - d[sel-3].fx;	tHat1.fy = d[sel-2].fy - d[sel-3].fy;
-	if(0.0 != (len = sqrt((tHat1.fx * tHat1.fx) + (tHat1.fy * tHat1.fy)))) {
-		tHat1.fx /= len;					tHat1.fy /= len;
-		}
 	tHat2.fx = d[sel+2].fx - d[sel+3].fx;	tHat2.fy = d[sel+2].fy - d[sel+3].fy;
-	if(0.0 != (len = sqrt((tHat2.fx * tHat2.fx) + (tHat2.fy * tHat2.fy)))) {
-		tHat2.fx /= len;					tHat2.fy /= len;
-		}
-	FitCubic(ndata, 0, 2, tHat1, tHat2, 1.0e-13);
-	nPoints = o_nPoints;
+	d[sel] = d[sel+3];
+	IpolBez(d+sel-3, tHat1, tHat2);
+}
+
+//heuristic interpolation: other methods failed
+void
+Bezier::IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2)
+{
+	double b0, b1, b2;						//temp variables
+
+	b1 = d[3].fx - d[0].fx;					b2 = d[3].fy - d[0].fy;
+	b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
+	b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+	b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+	d[1].fx = d[0].fx + tHat1.fx * b1;		d[1].fy = d[0].fy + tHat1.fy * b1;
+	d[2].fx = d[3].fx + tHat2.fx * b2;		d[2].fy = d[3].fy + tHat2.fy * b2;
 }
 
 //Fit a Bezier curve to a (sub)set of digitized points
@@ -6519,24 +7460,16 @@ void
 Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error)
 {
 	lfPOINT bezCurve[4];
-	double *u, *uPrime, maxError, iterationError;
+	double *u, *uPrime, maxError, iterationError, len;
 	int i, splitPoint, npt;
 	lfPOINT tHatCenter;
 	int maxIterations = 8;
-	double len, b0, b1, b2;				//temp variables
 
 	iterationError = error * error;
 	npt = last - first +1;
 	if(npt == 2) {
-		b1 = d[last].fx - d[first].fx;			b2 = d[last].fy - d[first].fy;
-		b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
-		b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
-		b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
 		bezCurve[0] = d[first];					bezCurve[3] = d[last];
-		bezCurve[1].fx = bezCurve[0].fx + tHat1.fx * b1;
-		bezCurve[1].fy = bezCurve[0].fy + tHat1.fy * b1;
-		bezCurve[2].fx = bezCurve[3].fx + tHat2.fx * b2;
-		bezCurve[2].fy = bezCurve[3].fy + tHat2.fy * b2;
+		IpolBez(bezCurve, tHat1, tHat2);
 		AddPoints(3, bezCurve);
 		return;
 		}
@@ -6544,6 +7477,9 @@ Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2,
 	GenerateBezier(d, first, last, u, tHat1, tHat2, bezCurve);
 	maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
 	if(maxError < error) {
+		if(maxError < 0.0) {					//Failure fitting curve
+			IpolBez(bezCurve, tHat1, tHat2);
+			}
 		AddPoints(3, bezCurve);					return;
 		}
 	if(maxError < iterationError) {
@@ -6552,6 +7488,7 @@ Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2,
 			GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
 			maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint);
 			if (maxError < error) {
+				if(maxError < 0.0) IpolBez(bezCurve, tHat1, tHat2);
 				AddPoints(3, bezCurve);			return;
 				}
 			free(u);							u = uPrime;
@@ -6702,363 +7639,373 @@ Bezier::ChordLengthParameterize(lfPOINT *d, int first, int last)
 	for(i = first +1; i <= last; i++) {
 		u[i-first] = u[i-first] / u[last-first];
 		}
-	return u;
+	return u;
+}
+
+double
+Bezier::ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint)
+{
+	int i;
+	double maxDist, dist;
+	lfPOINT P, v;
+
+	*splitPoint = (last - first + 1)>>1;
+	maxDist = -1.0;
+	for(i = first +1; i < last; i++) {
+		P = fBezier(3, bezCurve, u[i-first]);
+		v.fx = P.fx - d[i].fx;			v.fy = P.fy - d[i].fy;
+		dist = v.fx * v.fx + v.fy * v.fy;
+		if(dist >= maxDist) {
+			maxDist = dist;		*splitPoint = i;
+			}
+		}
+	return maxDist;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// polygons are based on the polyline object
+polygon::polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
+	polyline(par, d, fpts, cpts)
+{
+	Id = GO_POLYGON;
+	memcpy(&pgLine, defs.pgLineDEF(0L), sizeof(LineDEF));
+	type = 1;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// rectangle with absolute coordinates
+rectangle::rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2):
+	GraphObj(par, d)
+{
+	double dx = 0.0, dy = 0.0;
+
+	FileIO(INIT_VARS);
+	if(parent){
+		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+		}
+	memcpy(&fp1, p1, sizeof(lfPOINT));	memcpy(&fp2, p2, sizeof(lfPOINT));
+	fp1.fx -= dx;	fp1.fy -= dy;		fp2.fx -= dx;	fp2.fy -= dy;
+	type = 0;
+	Id = GO_RECTANGLE;
+	bModified = false;
+}
+
+rectangle::rectangle(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	type = 0;
+	bModified = false;
+}
+
+rectangle::~rectangle()
+{
+	Command(CMD_FLUSH, 0L, 0L);
+	if(bModified) Undo.InvalidGO(this);
+	if(drc) delete(drc);					drc = 0L;
+}
+
+double
+rectangle::GetSize(int select)
+{
+	if(parent && parent->Id== GO_GROUP){
+	switch(select) {
+		case SIZE_XPOS:		return fp1.fx + parent->GetSize(SIZE_XPOS);
+		case SIZE_XPOS+1:	return fp2.fx + parent->GetSize(SIZE_XPOS);
+		case SIZE_YPOS:		return fp1.fy + parent->GetSize(SIZE_YPOS);
+		case SIZE_YPOS+1:	return fp2.fy + parent->GetSize(SIZE_YPOS);
+		case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
+		case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
+			return parent->GetSize(select);
+			}
+		return 0.0;
+		}
+	switch(select) {
+	case SIZE_XPOS:		return fp1.fx;
+	case SIZE_XPOS+1:	return fp2.fx;
+	case SIZE_YPOS:		return fp1.fy;
+	case SIZE_YPOS+1:	return fp2.fy;
+	case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
+	case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
+		if(parent) return parent->GetSize(select);
+		break;
+		}
+	return 0.0;
+}
+
+bool
+rectangle::SetSize(int select, double value)
+{
+	switch(select & 0xfff) {
+	case SIZE_XPOS:				fp1.fx = value;			return true;
+	case SIZE_XPOS+1:			fp2.fx = value;			return true;
+	case SIZE_YPOS:				fp1.fy = value;			return true;
+	case SIZE_YPOS+1:			fp2.fy = value;			return true;
+		}
+	return false;
+}
+
+void 
+rectangle::DoMark(anyOutput *o, bool mark)
+{
+	RECT upd;
+
+	if(!drc) drc = new dragRect(this, 0);
+	memcpy(&upd, &rDims, sizeof(RECT));
+	if(mark){
+		if(drc) drc->DoPlot(o);
+		}
+	else if(parent)	parent->DoPlot(o);
+	IncrementMinMaxRect(&upd, 6);
+	o->UpdateRect(&upd, false);
+}
+
+void
+rectangle::DoPlot(anyOutput *o)
+{
+	int x1, y1, x2, y2;
+	double tmp, dx, dy;
+
+	if(!parent || !o) return;
+	dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+	if(fp1.fx > fp2.fx) {
+		tmp = fp2.fx;	fp2.fx = fp1.fx;	fp1.fx = tmp;
+		}
+	if(fp1.fy > fp2.fy) {
+		tmp = fp2.fy;	fp2.fy = fp1.fy;	fp1.fy = tmp;
+		}
+	if(type == 2) PlotRoundRect(o);
+	else {
+		x1 = o->co2ix(fp1.fx+dx);			y1 = o->co2iy(fp1.fy+dy);
+		x2 = o->co2ix(fp2.fx+dx);			y2 = o->co2iy(fp2.fy+dy);
+		o->SetLine(&Line);				o->SetFill(&Fill);
+		if(type == 1) o->oCircle(x1, y1, x2, y2, name);
+		else o->oRectangle(x1, y1, x2, y2, name);
+		SetMinMaxRect(&rDims, x1, y1, x2, y2);
+		}
+	o->MrkMode = MRK_NONE;
+	if(CurrGO == this) o->ShowMark(this, MRK_GODRAW);
+}
+
+bool
+rectangle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_FLUSH:
+		if(pts) free(pts);		pts = 0L;
+		if(name) free(name);	name = 0L;
+		return true;
+	case CMD_SCALE:
+		fp1.fx = ((scaleINFO*)tmpl)->sx.fx + fp1.fx * ((scaleINFO*)tmpl)->sx.fy;
+		fp2.fx = ((scaleINFO*)tmpl)->sx.fx + fp2.fx * ((scaleINFO*)tmpl)->sx.fy;
+		fp1.fy = ((scaleINFO*)tmpl)->sy.fx + fp1.fy * ((scaleINFO*)tmpl)->sy.fy;
+		fp2.fy = ((scaleINFO*)tmpl)->sy.fx + fp2.fy * ((scaleINFO*)tmpl)->sy.fy;
+		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+		FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;	FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;			rad *= ((scaleINFO*)tmpl)->sy.fy;
+		return true;
+	case CMD_SAVEPOS:
+		bModified = true;
+		Undo.SaveLFP(this, &fp1, 0L);
+		Undo.SaveLFP(this, &fp2, UNDO_CONTINUE);
+		return true;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
+				return o->ShowMark(this, MRK_GODRAW);
+				}
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		switch (type) {
+		case 1:		Id = GO_ELLIPSE;		break;
+		case 2:		Id = GO_ROUNDREC;		break;
+		default:	Id = GO_RECTANGLE;		break;
+			}
+		return true;
+	case CMD_MOVE:
+		bModified = true;
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		fp1.fx += ((lfPOINT*)tmpl)[0].fx;	fp1.fy += ((lfPOINT*)tmpl)[0].fy;
+		fp2.fx += ((lfPOINT*)tmpl)[0].fx;	fp2.fy += ((lfPOINT*)tmpl)[0].fy;
+		CurrGO = this;
+	case CMD_REDRAW:
+		if(parent && cmd != CMD_UNDO_MOVE){
+			parent->Command(CMD_REDRAW, tmpl, o);
+			}
+		return true;
+	case CMD_SETSCROLL:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		}
+	return false;
+}
+
+void
+rectangle::Track(POINT *p, anyOutput *o)
+{
+	POINT tpts[5];
+	RECT old_rc;
+	double dx, dy;
+
+	if(o && parent){
+		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(fp1.fx+dx)+p->x;		
+		tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(fp1.fy+dy)+p->y;
+		tpts[1].y = tpts[2].y = o->co2iy(fp2.fy+dy)+p->y;
+		tpts[2].x = tpts[3].x = o->co2ix(fp2.fx+dx)+p->x;
+		UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
+		UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);	
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		o->ShowLine(tpts, 5, Line.color);
+		if(type == 1) o->ShowEllipse(tpts[0], tpts[2], Line.color);
+		}
+}
+
+void *
+rectangle::ObjThere(int x, int y)
+{
+	if(drc) return drc->ObjThere(x, y);
+	return 0L;
+}
+
+//use circular Bresenham's algorithm to draw rounded rectangles
+//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+//   Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.; 
+//   ISBN 0-12-288165-5 
+void
+rectangle::PlotRoundRect(anyOutput *o)
+{
+	int i, m, x, y, di, de, lim, ir, x1, x2, y1, y2;
+	double dx, dy;
+	POINT np;
+
+	dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
+	ir = o->un2ix(rad);
+	x1 = o->co2ix(fp1.fx+dx);			y1 = o->co2iy(fp1.fy+dy);
+	x2 = o->co2ix(fp2.fx+dx);			y2 = o->co2iy(fp2.fy+dy);
+	if (x1 > x2) Swap(x1, x2);		if(y1 > y2) Swap(y1, y2);
+	if(pts) free(pts);				nPts = 0;
+	m = ir*4+10;
+	if(!(pts = (POINT*)malloc(m*sizeof(POINT))))return;
+	for(i = 0; i < 4; i++) {
+		x = lim = 0;	y = ir;	di = 2*(1-ir);
+		while (y >= lim){
+			if(di < 0) {
+				de = 2*di + 2*y -1;
+				if(de > 0) {
+					x++;	y--;	di += (2*x -2*y +2);
+					}
+				else {
+					x++;	di += (2*x +1);
+					}
+				}
+			else {
+				de = 2*di -2*x -1;
+				if(de > 0) {
+					y--;	di += (-2*y +1);
+					}
+				else {
+					x++;	y--;	di += (2*x -2*y +2);
+					}
+				}
+			switch(i) {
+			case 0:
+				np.x = x2-ir+x;		np.y = y2-ir+y;
+				break;
+			case 1:
+				np.x = x2-ir+y;		np.y = y1+ir-x;
+				break;
+			case 2: 
+				np.x = x1+ir-x;		np.y = y1+ir-y;
+				break;
+			case 3:
+				np.x = x1+ir-y;		np.y = y2-ir+x;
+				break;
+				}
+			AddToPolygon(&nPts, pts, &np);
+			}
+		}
+	AddToPolygon(&nPts, pts, pts);	//close polygon
+	o->SetLine(&Line);				o->SetFill(&Fill);
+	o->oPolygon(pts, nPts, name);
+	SetMinMaxRect(&rDims, x1, y1, x2, y2);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ellipse with absolute coordinates
+ellipse::ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
+	:rectangle(par, d, p1, p2)
+{
+	type = 1;
+	Id = GO_ELLIPSE;
+}
+
+ellipse::ellipse(int src)
+	:rectangle(src)
+{
+	type = 1;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// rounded rectangle
+roundrec::roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
+	:rectangle(par, d, p1, p2)
+{
+	type = 2;
+	Id = GO_ROUNDREC;
+}
+
+roundrec::roundrec(int src)
+	:rectangle(src)
+{
+	type = 2;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Add a legend to the graph
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fd, char *desc)
+	:GraphObj(par, d)
+{
+	FileIO(INIT_VARS);
+	if(!ld && !fd && lf) ld = lf;
+	if(ld) {
+		memcpy(&DataLine, ld, sizeof(LineDEF));
+		flags |= 0x01;
+		}
+	if(lf) memcpy(&OutLine, lf, sizeof(LineDEF));
+	if(fd) {
+		if(fd->hatch) memcpy(&HatchLine, fd->hatch, sizeof(LineDEF));
+		memcpy(&Fill, fd, sizeof(FillDEF));
+		Fill.hatch = &HatchLine;
+		flags |= 0x02;
+		}
+	DefDesc(desc);		Id = GO_LEGITEM;		moveable = 1;
 }
 
-double
-Bezier::ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint)
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy)
+	:GraphObj(par, d)
 {
-	int i;
-	double maxDist, dist;
-	lfPOINT P, v;
-
-	*splitPoint = (last - first + 1)>>1;
-	maxDist = 0.0;
-	for(i = first +1; i < last; i++) {
-		P = fBezier(3, bezCurve, u[i-first]);
-		v.fx = P.fx - d[i].fx;			v.fy = P.fy - d[i].fy;
-		dist = v.fx * v.fx + v.fy * v.fy;
-		if(dist >= maxDist) {
-			maxDist = dist;		*splitPoint = i;
-			}
+	FileIO(INIT_VARS);
+	if(ld) {
+		memcpy(&DataLine, ld, sizeof(LineDEF));		flags |= 0x01;
 		}
-	return maxDist;
+	if(sy) {
+		Sym = sy;		Sym->parent = this;			flags |= 0x04;
+		}
+	DefDesc(sy ? sy->name : 0L);		Id = GO_LEGITEM;		moveable = 1;
 }
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// polygons are based on the polyline object
-polygon::polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
-	polyline(par, d, fpts, cpts)
-{
-	Id = GO_POLYGON;
-	memcpy(&pgLine, defs.pgLineDEF(0L), sizeof(LineDEF));
-	type = 1;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// rectangle with absolute coordinates
-rectangle::rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2):
-	GraphObj(par, d)
-{
-	double dx = 0.0, dy = 0.0;
-
-	FileIO(INIT_VARS);
-	if(parent){
-		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-		}
-	memcpy(&fp1, p1, sizeof(lfPOINT));	memcpy(&fp2, p2, sizeof(lfPOINT));
-	fp1.fx -= dx;	fp1.fy -= dy;		fp2.fx -= dx;	fp2.fy -= dy;
-	type = 0;
-	Id = GO_RECTANGLE;
-	bModified = false;
-}
-
-rectangle::rectangle(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	type = 0;
-	bModified = false;
-}
-
-rectangle::~rectangle()
-{
-	Command(CMD_FLUSH, 0L, 0L);
-	if(bModified) Undo.InvalidGO(this);
-}
-
-double
-rectangle::GetSize(int select)
-{
-	if(parent && parent->Id== GO_GROUP){
-	switch(select) {
-		case SIZE_XPOS:		return fp1.fx + parent->GetSize(SIZE_XPOS);
-		case SIZE_XPOS+1:	return fp2.fx + parent->GetSize(SIZE_XPOS);
-		case SIZE_YPOS:		return fp1.fy + parent->GetSize(SIZE_YPOS);
-		case SIZE_YPOS+1:	return fp2.fy + parent->GetSize(SIZE_YPOS);
-		case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
-		case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
-			return parent->GetSize(select);
-			}
-		return 0.0;
-		}
-	switch(select) {
-	case SIZE_XPOS:		return fp1.fx;
-	case SIZE_XPOS+1:	return fp2.fx;
-	case SIZE_YPOS:		return fp1.fy;
-	case SIZE_YPOS+1:	return fp2.fy;
-	case SIZE_GRECT_LEFT:	case SIZE_GRECT_TOP:
-	case SIZE_GRECT_RIGHT:	case SIZE_GRECT_BOTTOM:
-		if(parent) return parent->GetSize(select);
-		break;
-		}
-	return 0.0;
-}
-
-bool
-rectangle::SetSize(int select, double value)
-{
-	switch(select & 0xfff) {
-	case SIZE_XPOS:				fp1.fx = value;			return true;
-	case SIZE_XPOS+1:			fp2.fx = value;			return true;
-	case SIZE_YPOS:				fp1.fy = value;			return true;
-	case SIZE_YPOS+1:			fp2.fy = value;			return true;
-		}
-	return false;
-}
-
-void 
-rectangle::DoMark(anyOutput *o, bool mark)
-{
-	RECT upd;
-
-	if(!drc) drc = new dragRect(this, 0);
-	memcpy(&upd, &rDims, sizeof(RECT));
-	if(mark){
-		if(drc) drc->DoPlot(o);
-		}
-	else if(parent)	parent->DoPlot(o);
-	IncrementMinMaxRect(&upd, 6);
-	o->UpdateRect(&upd, false);
-}
-
-void
-rectangle::DoPlot(anyOutput *o)
-{
-	int x1, y1, x2, y2;
-	double tmp, dx, dy;
-
-	if(!parent || !o) return;
-	dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
-	if(fp1.fx > fp2.fx) {
-		tmp = fp2.fx;	fp2.fx = fp1.fx;	fp1.fx = tmp;
-		}
-	if(fp1.fy > fp2.fy) {
-		tmp = fp2.fy;	fp2.fy = fp1.fy;	fp1.fy = tmp;
-		}
-	if(type == 2) PlotRoundRect(o);
-	else {
-		x1 = o->co2ix(fp1.fx+dx);			y1 = o->co2iy(fp1.fy+dy);
-		x2 = o->co2ix(fp2.fx+dx);			y2 = o->co2iy(fp2.fy+dy);
-		o->SetLine(&Line);				o->SetFill(&Fill);
-		if(type == 1) o->oCircle(x1, y1, x2, y2, name);
-		else o->oRectangle(x1, y1, x2, y2, name);
-		SetMinMaxRect(&rDims, x1, y1, x2, y2);
-		}
-	o->MrkMode = MRK_NONE;
-	if(CurrGO == this) o->ShowMark(this, MRK_GODRAW);
-}
-
-bool
-rectangle::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_FLUSH:
-		if(pts) free(pts);		pts = 0L;
-		if(name) free(name);	name = 0L;
-		return true;
-	case CMD_SAVEPOS:
-		bModified = true;
-		Undo.SaveLFP(this, &fp1, 0L);
-		Undo.SaveLFP(this, &fp2, UNDO_CONTINUE);
-		return true;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
-				return o->ShowMark(this, MRK_GODRAW);
-				}
-			}
-		return false;
-	case CMD_SET_DATAOBJ:
-		switch (type) {
-		case 1:		Id = GO_ELLIPSE;		break;
-		case 2:		Id = GO_ROUNDREC;		break;
-		default:	Id = GO_RECTANGLE;		break;
-			}
-		return true;
-	case CMD_MOVE:
-		bModified = true;
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		fp1.fx += ((lfPOINT*)tmpl)[0].fx;	fp1.fy += ((lfPOINT*)tmpl)[0].fy;
-		fp2.fx += ((lfPOINT*)tmpl)[0].fx;	fp2.fy += ((lfPOINT*)tmpl)[0].fy;
-		CurrGO = this;
-	case CMD_REDRAW:
-		if(parent && cmd != CMD_UNDO_MOVE){
-			parent->Command(CMD_REDRAW, tmpl, o);
-			}
-		return true;
-	case CMD_SETSCROLL:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		}
-	return false;
-}
-
-void
-rectangle::Track(POINT *p, anyOutput *o)
-{
-	POINT tpts[5];
-	RECT old_rc;
-	double dx, dy;
-
-	if(o && parent){
-		dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		o->UpdateRect(&rDims, false);
-		tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(fp1.fx+dx)+p->x;		
-		tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(fp1.fy+dy)+p->y;
-		tpts[1].y = tpts[2].y = o->co2iy(fp2.fy+dy)+p->y;
-		tpts[2].x = tpts[3].x = o->co2ix(fp2.fx+dx)+p->x;
-		UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
-		UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);	
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		o->ShowLine(tpts, 5, Line.color);
-		if(type == 1) o->ShowEllipse(tpts[0], tpts[2], Line.color);
-		}
-}
-
-void *
-rectangle::ObjThere(int x, int y)
-{
-	if(drc) return drc->ObjThere(x, y);
-	return 0L;
-}
-
-//use circular Bresenham's algorithm to draw rounded rectangles
-//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
-//   Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.; 
-//   ISBN 0-12-288165-5 
-void
-rectangle::PlotRoundRect(anyOutput *o)
-{
-	int i, m, x, y, di, de, lim, ir, x1, x2, y1, y2;
-	double dx, dy;
-	POINT np;
-
-	dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
-	ir = o->un2ix(rad);
-	x1 = o->co2ix(fp1.fx+dx);			y1 = o->co2iy(fp1.fy+dy);
-	x2 = o->co2ix(fp2.fx+dx);			y2 = o->co2iy(fp2.fy+dy);
-	if (x1 > x2) Swap(x1, x2);		if(y1 > y2) Swap(y1, y2);
-	if(pts) free(pts);				nPts = 0;
-	m = ir*4+10;
-	if(!(pts = (POINT*)malloc(m*sizeof(POINT))))return;
-	for(i = 0; i < 4; i++) {
-		x = lim = 0;	y = ir;	di = 2*(1-ir);
-		while (y >= lim){
-			if(di < 0) {
-				de = 2*di + 2*y -1;
-				if(de > 0) {
-					x++;	y--;	di += (2*x -2*y +2);
-					}
-				else {
-					x++;	di += (2*x +1);
-					}
-				}
-			else {
-				de = 2*di -2*x -1;
-				if(de > 0) {
-					y--;	di += (-2*y +1);
-					}
-				else {
-					x++;	y--;	di += (2*x -2*y +2);
-					}
-				}
-			switch(i) {
-			case 0:
-				np.x = x2-ir+x;		np.y = y2-ir+y;
-				break;
-			case 1:
-				np.x = x2-ir+y;		np.y = y1+ir-x;
-				break;
-			case 2: 
-				np.x = x1+ir-x;		np.y = y1+ir-y;
-				break;
-			case 3:
-				np.x = x1+ir-y;		np.y = y2-ir+x;
-				break;
-				}
-			AddToPolygon(&nPts, pts, &np);
-			}
-		}
-	AddToPolygon(&nPts, pts, pts);	//close polygon
-	o->SetLine(&Line);				o->SetFill(&Fill);
-	o->oPolygon(pts, nPts, name);
-	SetMinMaxRect(&rDims, x1, y1, x2, y2);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// ellipse with absolute coordinates
-ellipse::ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
-	:rectangle(par, d, p1, p2)
-{
-	type = 1;
-	Id = GO_ELLIPSE;
-}
-
-ellipse::ellipse(int src)
-	:rectangle(src)
-{
-	type = 1;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// rounded rectangle
-roundrec::roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
-	:rectangle(par, d, p1, p2)
-{
-	type = 2;
-	Id = GO_ROUNDREC;
-}
-
-roundrec::roundrec(int src)
-	:rectangle(src)
-{
-	type = 2;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Add a legend to the graph
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fd)
-	:GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	if(!ld && !fd && lf) ld = lf;
-	if(ld) {
-		memcpy(&DataLine, ld, sizeof(LineDEF));
-		flags |= 0x01;
-		}
-	if(lf) memcpy(&OutLine, lf, sizeof(LineDEF));
-	if(fd) {
-		if(fd->hatch) memcpy(&HatchLine, fd->hatch, sizeof(LineDEF));
-		memcpy(&Fill, fd, sizeof(FillDEF));
-		Fill.hatch = &HatchLine;
-		flags |= 0x02;
-		}
-	DefDesc(0L);		Id = GO_LEGITEM;		moveable = true;
-}
-
-LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy)
-	:GraphObj(par, d)
-{
-	FileIO(INIT_VARS);
-	if(ld) {
-		memcpy(&DataLine, ld, sizeof(LineDEF));		flags |= 0x01;
-		}
-	if(sy) {
-		Sym = sy;		Sym->parent = this;			flags |= 0x04;
-		}
-	DefDesc(0L);		Id = GO_LEGITEM;		moveable = true;
-}
-
 LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc)
 	:GraphObj(par, d)
 {
@@ -7066,56 +8013,55 @@ LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc)
 	if(ld) {
 		memcpy(&OutLine, ld, sizeof(LineDEF));
 		}
-	DefDesc(desc);		Id = GO_LEGITEM;		moveable = true;
-}
-
-LegItem::LegItem(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	moveable = true;
-}
-
-LegItem::~LegItem()
-{
-	if(Sym) DeleteGO(Sym);		Sym = 0L;
-	if(Desc) DeleteGO(Desc);	Desc = 0L;
-}
-
-double
-LegItem::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_XCENTER:
+	DefDesc(desc);		Id = GO_LEGITEM;		moveable = 1;
+}
+
+LegItem::LegItem(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	moveable = 1;
+}
+
+LegItem::~LegItem()
+{
+	if(Sym) DeleteGO(Sym);		Sym = 0L;
+	if(Desc) DeleteGO(Desc);	Desc = 0L;
+}
+
+double
+LegItem::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XCENTER:
 		return (parent->GetSize((flags & 0x01) ? SIZE_XPOS+2 : SIZE_XPOS) + 
 			parent->GetSize((flags & 0x01) ? SIZE_XPOS+3 : SIZE_XPOS+1))/2.0;
-	case SIZE_YCENTER:
-		return (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-	case SIZE_LB_XPOS:		case SIZE_LB_YPOS:
-	case SIZE_GRECT_TOP:	case SIZE_GRECT_LEFT:
-	default:
-		if(parent) return parent->GetSize(select);
-		break;
-		}
-	return 0.0;
-}
-
-void
-LegItem::DoPlot(anyOutput *o)
-{
+	case SIZE_YCENTER:
+		return (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+	case SIZE_LB_XPOS:		case SIZE_LB_YPOS:
+	case SIZE_GRECT_TOP:	case SIZE_GRECT_LEFT:
+	default:
+		if(parent) return parent->GetSize(select);
+		break;
+		}
+	return 0.0;
+}
+
+void
+LegItem::DoPlot(anyOutput *o)
+{
 	POINT pts[3];
 	int ie, cy;
 
 	if(!parent || !o) return;
 	hcr.top = iround(parent->GetSize(SIZE_YPOS));
 	hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
-	SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
 	if(flags & 0x80) {
 		hcr.left = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+2 : SIZE_XPOS));
 		hcr.right = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+3 :SIZE_XPOS+1));
-		ie = o->un2ix(defs.GetSize(SIZE_ERRBAR)/2.0);
+		ie = o->un2ix(DefSize(SIZE_ERRBAR)/2.0);
 		o->SetLine(&OutLine);						cy = (hcr.top + hcr.bottom)>>1;
 		if((flags & 0x3f) == 0x01) {
 			pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
@@ -7172,101 +8118,110 @@ LegItem::DoPlot(anyOutput *o)
 			if(Sym) Sym->DoPlot(o);
 			}
 		}
+	SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
 	if(Desc) {
-		Desc->moveable = false;	Desc->DoPlot(o);
+		Desc->moveable = 1;			Desc->DoPlot(o);
 		if(Desc->rDims.bottom > rDims.bottom){
 			parent->SetSize(SIZE_YPOS+1, (double)Desc->rDims.bottom);
 			}
 		UpdateMinMaxRect(&rDims, Desc->rDims.left, Desc->rDims.top);
 		UpdateMinMaxRect(&rDims, Desc->rDims.right, Desc->rDims.bottom);
 		}
-}
-
-void
-LegItem::DoMark(anyOutput *o, bool mark)
-{
-	RECT cr;
-	LineDEF ld = {0.0, 1.0, 0x00000000L, 0x00000000L};
-	POINT pts[5];
-
-	if(!parent || !o) return;
-	cr.left = hcr.left-5;			cr.right = hcr.right+3;
-	cr.top = hcr.top-3;				cr.bottom = hcr.bottom+1;
-	ld.color = mark ? 0x00000000L : 0x00ffffffL;	o->SetLine(&ld);
-	pts[0].x = pts[3].x = pts[4].x = cr.left;	pts[0].y = pts[1].y = pts[4].y = cr.top;
-	pts[1].x = pts[2].x = cr.right;				pts[2].y = pts[3].y = cr.bottom;
-	o->oPolyline(pts, 5, name);					IncrementMinMaxRect(&cr, 3);
-	o->UpdateRect(&cr, false);
-}
-
-bool
-LegItem::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	GraphObj **tmpPlots;
-
-	switch(cmd){
-	case CMD_MOUSE_EVENT:
-		if(tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y) && o) {
-			if(Desc && Desc->Command(cmd, tmpl, o)) return true;
-			if(!CurrGO) o->ShowMark(CurrGO=this, MRK_GODRAW);
-			}
-		break;
-	case CMD_HIDE_MARK:
-		if(!tmpl || !o) return false;
-		if(Desc && Desc == (void*)tmpl) {
-			Desc->DoMark(o, false);
-			return true;
-			}
-		return false;
-	case CMD_REDRAW:	case CMD_MOVE:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		break;
-	case CMD_MUTATE:
-		if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
-		if(Desc == tmpPlots[0]) {
-			Undo.MutateGO((GraphObj**)&Desc, tmpPlots[1], 0L, o);
-			return true;
-			}
-		break;
-	case CMD_SET_DATAOBJ:
+}
+
+void
+LegItem::DoMark(anyOutput *o, bool mark)
+{
+	RECT cr;
+	LineDEF ld = {0.0, 1.0, 0x00000000L, 0x00000000L};
+	POINT pts[5];
+
+	if(!parent || !o) return;
+	cr.left = hcr.left-5;			cr.right = hcr.right+3;
+	cr.top = hcr.top-3;				cr.bottom = hcr.bottom+1;
+	ld.color = mark ? 0x00000000L : 0x00ffffffL;	o->SetLine(&ld);
+	pts[0].x = pts[3].x = pts[4].x = cr.left;	pts[0].y = pts[1].y = pts[4].y = cr.top;
+	pts[1].x = pts[2].x = cr.right;				pts[2].y = pts[3].y = cr.bottom;
+	o->oPolyline(pts, 5, name);					IncrementMinMaxRect(&cr, 3);
+	o->UpdateRect(&cr, false);
+}
+
+bool
+LegItem::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	GraphObj **tmpPlots;
+
+	switch(cmd){
+	case CMD_MOUSE_EVENT:
+		if(tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y) && o) {
+			if(Desc && Desc->Command(cmd, tmpl, o)) return true;
+			if(!CurrGO) o->ShowMark(CurrGO=this, MRK_GODRAW);
+			}
+		break;
+	case CMD_HIDE_MARK:
+		if(!tmpl || !o) return false;
+		if(Desc && Desc == (void*)tmpl) {
+			Desc->DoMark(o, false);
+			return true;
+			}
+		return false;
+	case CMD_SCALE:
+		DataLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;		DataLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		OutLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;			OutLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;		HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+		Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;	
+		if(Sym) Sym->Command(cmd, tmpl, o);
+		if(Desc) Desc->Command(cmd, tmpl, o);
+		break;
+	case CMD_REDRAW:	case CMD_MOVE:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_MUTATE:
+		if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+		if(Desc == tmpPlots[0]) {
+			Undo.MutateGO((GraphObj**)&Desc, tmpPlots[1], 0L, o);
+			return true;
+			}
+		break;
+	case CMD_SET_DATAOBJ:
 		if(Desc) Desc->Command(cmd, tmpl, o);
-		Id = GO_LEGITEM;
-		data = (DataObj *)tmpl;
-		return true;
-		}
-	return false;
-}
-
-void
-LegItem::Track(POINT *p, anyOutput *o)
-{
-	if(parent) parent->Track(p, o);
-}
-
-bool
-LegItem::HasFill(LineDEF *ld, FillDEF *fd)
-{
-	if(ld && cmpLineDEF(ld, &OutLine)) return false;
-	if(fd && cmpFillDEF(fd, &Fill)) return false;
-	if(fd && fd->hatch && cmpLineDEF(fd->hatch, &HatchLine)) return false;
-	return true;
-}
-
-bool
-LegItem::HasSym(LineDEF *ld, GraphObj *sy)
-{
+		Id = GO_LEGITEM;
+		data = (DataObj *)tmpl;
+		return true;
+		}
+	return false;
+}
+
+void
+LegItem::Track(POINT *p, anyOutput *o)
+{
+	if(parent) parent->Track(p, o);
+}
+
+bool
+LegItem::HasFill(LineDEF *ld, FillDEF *fd, char *desc)
+{
+	if(ld && cmpLineDEF(ld, &OutLine)) return false;
+	if(fd && cmpFillDEF(fd, &Fill)) return false;
+	if(fd && fd->hatch && cmpLineDEF(fd->hatch, &HatchLine)) return false;
+	return true;
+}
+
+bool
+LegItem::HasSym(LineDEF *ld, GraphObj *sy)
+{
 	if(sy && !Sym) return false;
 	if(sy->Id == GO_SYMBOL && (sy->type & 0xfff) != (Sym->type & 0xfff)) return false;
-	if(sy && Sym) {
-		if(Sym->GetSize(SIZE_SYMBOL) != sy->GetSize(SIZE_SYMBOL)) return false;
-		if(Sym->GetSize(SIZE_SYM_LINE) != sy->GetSize(SIZE_SYM_LINE)) return false;
-		if(Sym->GetColor(COL_SYM_LINE) != sy->GetColor(COL_SYM_LINE)) return false;
-		if(Sym->GetColor(COL_SYM_FILL) != sy->GetColor(COL_SYM_FILL)) return false;
-		}
-	if(ld && cmpLineDEF(ld, &DataLine)) return false;
-	return true;
-}
-
+	if(sy && Sym) {
+		if(Sym->GetSize(SIZE_SYMBOL) != sy->GetSize(SIZE_SYMBOL)) return false;
+		if(Sym->GetSize(SIZE_SYM_LINE) != sy->GetSize(SIZE_SYM_LINE)) return false;
+		if(Sym->GetColor(COL_SYM_LINE) != sy->GetColor(COL_SYM_LINE)) return false;
+		if(Sym->GetColor(COL_SYM_FILL) != sy->GetColor(COL_SYM_FILL)) return false;
+		}
+	if(ld && cmpLineDEF(ld, &DataLine)) return false;
+	return true;
+}
+
 bool
 LegItem::HasErr(LineDEF *ld, int err)
 {
@@ -7274,255 +8229,278 @@ LegItem::HasErr(LineDEF *ld, int err)
 	if(ld && cmpLineDEF(ld, &OutLine)) return false;
 	return true;
 }
-
-void
-LegItem::DefDesc(char *txt)
-{
-	TextDEF td;
-
-	td.ColTxt = 0x00000000L;		td.ColBg = 0x00ffffffL;
-	td.fSize = defs.GetSize(SIZE_TICK_LABELS);
-	td.RotBL = td.RotCHAR = 0.0;
-	td.iSize = 0;					td.Align = TXA_VTOP | TXA_HLEFT;
-	td.Mode = TXM_TRANSPARENT;		td.Style = TXS_NORMAL;
-	td.Font = FONT_HELVETICA;		td.text = txt ? strdup(txt) : strdup("text");
-	Desc = new Label(this, data, 0, 0, &td, LB_X_PARENT | LB_Y_PARENT);
-}
-
-Legend::Legend(GraphObj *par, DataObj *d):GraphObj(par, d)
-{
-	FileIO(INIT_VARS);		Id = GO_LEGEND;		moveable = true;
-}
-
-Legend::Legend(int src):GraphObj(0L, 0L)
-{
-	FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		}
-	moveable = true;
-}
-
-Legend::~Legend()
-{
-	int i;
-
-	if(Items) {
-		for(i = 0; i< nItems; i++) if(Items[i]) DeleteGO(Items[i]);
-		free(Items);	Items = 0L;
-		}
-	if(to) DelBitmapClass(to);		to = 0L;
-}
-double
-Legend::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_XPOS:		return C_Rect.Xmin;
-	case SIZE_XPOS+1:	return C_Rect.Xmax;
+
+void
+LegItem::DefDesc(char *txt)
+{
+	TextDEF td;
+	int cb;
+
+	cb = txt && *txt ? (int)strlen(txt) : 20;
+	if(cb < 20) cb = 20;
+	td.ColTxt = 0x00000000L;		td.ColBg = 0x00ffffffL;
+	td.fSize = DefSize(SIZE_TICK_LABELS);
+	td.RotBL = td.RotCHAR = 0.0;
+	td.iSize = 0;					td.Align = TXA_VTOP | TXA_HLEFT;
+	td.Mode = TXM_TRANSPARENT;		td.Style = TXS_NORMAL;
+	td.Font = FONT_HELVETICA;		td.text = (char*)malloc(cb+2);
+	rlp_strcpy(td.text, cb+2, txt ? txt : (char*)"text");
+	Desc = new Label(this, data, 0, 0, &td, LB_X_PARENT | LB_Y_PARENT);
+}
+
+Legend::Legend(GraphObj *par, DataObj *d):GraphObj(par, d)
+{
+	FileIO(INIT_VARS);		Id = GO_LEGEND;		moveable = true;
+}
+
+Legend::Legend(int src):GraphObj(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+	moveable = true;
+}
+
+Legend::~Legend()
+{
+	int i;
+
+	if(Items) {
+		for(i = 0; i< nItems; i++) if(Items[i]) DeleteGO(Items[i]);
+		free(Items);	Items = 0L;
+		}
+	if(to) DelBitmapClass(to);		to = 0L;
+}
+double
+Legend::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XPOS:		return C_Rect.Xmin;
+	case SIZE_XPOS+1:	return C_Rect.Xmax;
 	case SIZE_XPOS+2:	return E_Rect.Xmin;
 	case SIZE_XPOS+3:	return E_Rect.Xmax;
-	case SIZE_YPOS:		return C_Rect.Ymin;
+	case SIZE_YPOS:		return C_Rect.Ymin;
 	case SIZE_YPOS+1:	return C_Rect.Ymax;
-	case SIZE_LB_XPOS:	return lb_pos.fx;
-	case SIZE_LB_YPOS:	return lb_pos.fy;
-	case SIZE_GRECT_TOP:	case SIZE_GRECT_LEFT:
-		if(parent) return parent->GetSize(select);
-		break;
-		}
-	return 0.0;
-}
-
-bool
-Legend::SetSize(int select, double value)
-{
-	double tmp;
-
-	switch (select & 0xfff){
-	case SIZE_XPOS:		pos.fx = value;		return true;
-	case SIZE_YPOS:		pos.fy = value;		return true;
-	case SIZE_YPOS+1:
-		tmp = value - C_Rect.Ymax;
-		C_Rect.Ymin += tmp;		C_Rect.Ymax += tmp;		lb_pos.fy +=tmp;
-		}
-	return false;
-}
-
-void
-Legend::DoPlot(anyOutput *o)
-{
-	int i;
-	double y_inc, dx, dy;
-
-	if(!o || !Items) return;
-	if(to) DelBitmapClass(to);		to = 0L;
+	case SIZE_LB_XPOS:	return lb_pos.fx;
+	case SIZE_LB_YPOS:	return lb_pos.fy;
+	case SIZE_GRECT_TOP:	case SIZE_GRECT_LEFT:
+		if(parent) return parent->GetSize(select);
+		break;
+		}
+	return 0.0;
+}
+
+bool
+Legend::SetSize(int select, double value)
+{
+	double tmp;
+
+	switch (select & 0xfff){
+	case SIZE_XPOS:		pos.fx = value;		return true;
+	case SIZE_YPOS:		pos.fy = value;		return true;
+	case SIZE_YPOS+1:
+		tmp = value - C_Rect.Ymax;
+		C_Rect.Ymin += tmp;		C_Rect.Ymax += tmp;		lb_pos.fy +=tmp;
+		}
+	return false;
+}
+
+void
+Legend::DoPlot(anyOutput *o)
+{
+	int i;
+	double y_inc, dx, dy;
+
+	if(!o || !Items) return;
+	if(to) DelBitmapClass(to);		to = 0L;
 	dx = parent->GetSize(SIZE_GRECT_LEFT);		dy = parent->GetSize(SIZE_GRECT_TOP);
-	C_Rect.Xmin = o->co2fix(pos.fx + B_Rect.Xmin + D_Rect.Xmin + dx);
-	C_Rect.Ymin = o->co2fiy(pos.fy + B_Rect.Ymin + D_Rect.Ymin + dy);
-	C_Rect.Xmax = C_Rect.Xmin + o->un2fix(D_Rect.Xmax - D_Rect.Xmin);
+	C_Rect.Xmin = o->co2fix(pos.fx + B_Rect.Xmin + D_Rect.Xmin + dx);
+	C_Rect.Ymin = o->co2fiy(pos.fy + B_Rect.Ymin + D_Rect.Ymin + dy);
+	C_Rect.Xmax = C_Rect.Xmin + o->un2fix(D_Rect.Xmax - D_Rect.Xmin);
 	C_Rect.Ymax = C_Rect.Ymin + o->un2fix(D_Rect.Ymax - D_Rect.Ymin);
-	E_Rect.Ymin = C_Rect.Ymin;	E_Rect.Ymax = C_Rect.Ymax;
+	E_Rect.Ymin = C_Rect.Ymin;	E_Rect.Ymax = C_Rect.Ymax;
 	E_Rect.Xmin = o->co2fix(pos.fx + B_Rect.Xmin + F_Rect.Xmin + dx);
 	E_Rect.Xmax = E_Rect.Xmin + o->un2fix(F_Rect.Xmax - F_Rect.Xmin);
-	y_inc = floor(0.5+o->un2fiy(B_Rect.Ymax - B_Rect.Ymin));
-	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
-	lb_pos.fx = o->co2fix(pos.fx + B_Rect.Xmax + dx);	lb_pos.fy = C_Rect.Ymin;
-	//draw all items
-	for(i = 0; i < nItems; i++) {
-		if(Items[i]){
+	y_inc = floor(0.5+o->un2fiy(B_Rect.Ymax - B_Rect.Ymin));
+	rDims.top = iround(C_Rect.Ymin); rDims.bottom = iround(C_Rect.Ymax);
+	rDims.left = rDims.right = iround(C_Rect.Xmin);	
+	lb_pos.fx = o->co2fix(pos.fx + B_Rect.Xmax + dx);	lb_pos.fy = C_Rect.Ymin;
+	//draw all items
+	for(i = 0; i < nItems; i++) {
+		if(Items[i]){
 			if((Items[i]->flags & 0x11) == 0x01) hasLine = true;
-			Items[i]->DoPlot(o);
-			if(rDims.left == rDims.right || rDims.top == rDims.bottom){
-				rDims.left = Items[i]->rDims.left;	rDims.right = Items[i]->rDims.right;
-				rDims.top = Items[i]->rDims.top;	rDims.bottom = Items[i]->rDims.bottom;
-				}
-			else {
-				UpdateMinMaxRect(&rDims, Items[i]->rDims.left, Items[i]->rDims.top);
-				UpdateMinMaxRect(&rDims, Items[i]->rDims.right, Items[i]->rDims.bottom);
-				}
-			C_Rect.Ymin += y_inc;		C_Rect.Ymax += y_inc;
-			lb_pos.fy += y_inc;
-			}
-		}
-	IncrementMinMaxRect(&rDims, 6);
-}
-
-void
-Legend::DoMark(anyOutput *o, bool mark)
-{
-	RECT cr;
-	LineDEF ld = {0.0, 1.0, 0x00c0c0c0L, 0x00000000L};
-	POINT pts[5];
-
-	if(!parent || !o) return;
-	cr.left = rDims.left;			cr.right = rDims.right;
-	cr.top = rDims.top;				cr.bottom = rDims.bottom;
-	ld.color = mark ? 0x00c0c0c0L : 0x00ffffffL;	o->SetLine(&ld);
-	pts[0].x = pts[3].x = pts[4].x = cr.left;	pts[0].y = pts[1].y = pts[4].y = cr.top;
-	pts[1].x = pts[2].x = cr.right;				pts[2].y = pts[3].y = cr.bottom;
-	o->oPolyline(pts, 5, name);					IncrementMinMaxRect(&cr, 3);
-	o->UpdateRect(&cr, false);
-}
-
-bool
-Legend::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i;
-
-	switch(cmd){
-	case CMD_MOUSE_EVENT:
-		if(o && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) {
-			if(Items) for(i = 0; i< nItems; i++) 
-				if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
-			if(!CurrGO) o->ShowMark(CurrGO = this, MRK_GODRAW);
-			}
-		break;
-	case CMD_SET_DATAOBJ:
-		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
-		Id = GO_LEGEND;
-		data = (DataObj *)tmpl;
-		return true;
-	case CMD_HIDE_MARK:
-		if(!tmpl || !o) return false;
-		if(Items && nItems) for(i = 0; i < nItems; i++) {
-			if(Items[i]) {
-				if(tmpl == (void*)Items[i]) {
-					Items[i]->DoMark(o, false);
-					return true;
-					}	
-				else if(Items[i]->Command(cmd, tmpl, o)) return true;
-				}
-			}
-		return false;
-	case CMD_DELOBJ:
-		o->HideMark();
-		if(Items && parent) for(i = 0; i < nItems; i++) {
-			if(Items[i] && tmpl == (void *)Items[i]) {
-				Undo.DeleteGO((GraphObj**)(&Items[i]), 0L, o);
-				parent->Command(CMD_REDRAW, NULL, o);
-				return true;
-				}
-			}
-		break;
-	case CMD_MOVE:
-		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
-	case CMD_UNDO_MOVE:
-		pos.fx += ((lfPOINT*)tmpl)[0].fx;	pos.fy += ((lfPOINT*)tmpl)[0].fy;
-		CurrGO = this;
-	case CMD_REDRAW:
-		if(parent && cmd != CMD_UNDO_MOVE){
-			parent->Command(CMD_REDRAW, tmpl, o);
-			}
-		return true;
-	case CMD_DROP_OBJECT:
-		if(!tmpl) return false;
-		if(!(Items = (LegItem**)realloc(Items, (2+nItems)*sizeof(LegItem*))))return false;
-		Items[nItems++] = (LegItem*)tmpl;
-		Items[nItems-1]->parent = this;
-		return true;
-		}
-	return false;
-}
-
-void
-Legend::Track(POINT *p, anyOutput *o)
-{
-	POINT pts[5];
-	LineDEF tld = {0.0, 1.0, 0x00c0c0c0, 0x0L};
-
-	if(!p || !o) return;
-	if(to) {
-		o->CopyBitmap(trc.left, trc.top, to, 0, 0, trc.right - trc.left, 
-			trc.bottom - trc.top, false);
-		DelBitmapClass(to);		to = 0L;
-		o->UpdateRect(&trc, false);
-		}
-	trc.left = pts[0].x = pts[1].x = pts[4].x = rDims.left + p->x;		
-	trc.top = pts[0].y = pts[3].y = pts[4].y = rDims.top + p->y;
-	trc.bottom = pts[1].y = pts[2].y = rDims.bottom + p->y;
-	trc.right = pts[2].x = pts[3].x = rDims.right + p->x;
-	IncrementMinMaxRect(&trc, 3);	to = GetRectBitmap(&trc, o);
-	o->SetLine(&tld);				o->oPolyline(pts, 5, 0L);
-	o->UpdateRect(&trc, false);
-} 
-
-bool
-Legend::HasFill(LineDEF *ld, FillDEF *fd)
-{
-	int i;
-	LegItem *li;
-
-	if(Items) for(i = 0; i < nItems; i++) {
-		if(Items[i] && Items[i]->HasFill(ld, fd)) return true;
-		}
-	if(li = new LegItem(this, data, 0L, ld, fd)){
-		if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
-		}
-	return false;
-}
-
-bool
-Legend::HasSym(LineDEF *ld, GraphObj *sy)
-{
-	int i, sym;
-	Symbol *ns;
-	LegItem *li;
-
-	if(!parent || !sy) return true;
+			Items[i]->DoPlot(o);
+			UpdateMinMaxRect(&rDims, Items[i]->rDims.left, Items[i]->rDims.top);
+			UpdateMinMaxRect(&rDims, Items[i]->rDims.right, Items[i]->rDims.bottom);
+			C_Rect.Ymin += y_inc;		C_Rect.Ymax += y_inc;
+			lb_pos.fy += y_inc;
+			}
+		}
+	IncrementMinMaxRect(&rDims, 6);
+}
+
+void
+Legend::DoMark(anyOutput *o, bool mark)
+{
+	RECT cr;
+	LineDEF ld = {0.0, 1.0, 0x00c0c0c0L, 0x00000000L};
+	POINT pts[5];
+
+	if(!parent || !o) return;
+	cr.left = rDims.left;			cr.right = rDims.right;
+	cr.top = rDims.top;				cr.bottom = rDims.bottom;
+	ld.color = mark ? 0x00c0c0c0L : 0x00ffffffL;	o->SetLine(&ld);
+	pts[0].x = pts[3].x = pts[4].x = cr.left;	pts[0].y = pts[1].y = pts[4].y = cr.top;
+	pts[1].x = pts[2].x = cr.right;				pts[2].y = pts[3].y = cr.bottom;
+	o->oPolyline(pts, 5, name);					IncrementMinMaxRect(&cr, 3);
+	o->UpdateRect(&cr, false);
+}
+
+bool
+Legend::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i;
+
+	switch(cmd){
+	case CMD_MOUSE_EVENT:
+		if(o && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) {
+			if(Items) for(i = 0; i< nItems; i++) 
+				if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
+			if(!CurrGO) o->ShowMark(CurrGO = this, MRK_GODRAW);
+			}
+		break;
+	case CMD_SET_DATAOBJ:
+		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
+		Id = GO_LEGEND;
+		data = (DataObj *)tmpl;
+		return true;
+	case CMD_SCALE:
+		pos.fx *= ((scaleINFO*)tmpl)->sx.fy;			pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
+		lb_pos.fx *= ((scaleINFO*)tmpl)->sx.fy;			lb_pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
+		B_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy;		B_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+		B_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy;		B_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+		C_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy;		C_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+		C_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy;		C_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+		D_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy;		D_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+		D_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy;		D_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+		E_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy;		E_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+		E_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy;		E_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+		F_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy;		F_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+		F_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy;		F_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
+		return true;
+	case CMD_HIDE_MARK:
+		if(!tmpl || !o) return false;
+		if(Items && nItems) for(i = 0; i < nItems; i++) {
+			if(Items[i]) {
+				if(tmpl == (void*)Items[i]) {
+					Items[i]->DoMark(o, false);
+					return true;
+					}	
+				else if(Items[i]->Command(cmd, tmpl, o)) return true;
+				}
+			}
+		return false;
+	case CMD_DELOBJ:
+		o->HideMark();
+		if(Items && parent) for(i = 0; i < nItems; i++) {
+			if(Items[i] && tmpl == (void *)Items[i]) {
+				Undo.DeleteGO((GraphObj**)(&Items[i]), 0L, o);
+				parent->Command(CMD_REDRAW, NULL, o);
+				return true;
+				}
+			}
+		break;
+	case CMD_MOVE:
+		Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+	case CMD_UNDO_MOVE:
+		pos.fx += ((lfPOINT*)tmpl)[0].fx;	pos.fy += ((lfPOINT*)tmpl)[0].fy;
+		CurrGO = this;
+	case CMD_REDRAW:
+		if(parent && cmd != CMD_UNDO_MOVE){
+			parent->Command(CMD_REDRAW, tmpl, o);
+			}
+		return true;
+	case CMD_DROP_OBJECT:
+		if(!tmpl) return false;
+		if(!(Items = (LegItem**)realloc(Items, (2+nItems)*sizeof(LegItem*))))return false;
+		Items[nItems++] = (LegItem*)tmpl;
+		Items[nItems-1]->parent = this;
+		return true;
+		}
+	return false;
+}
+
+void
+Legend::Track(POINT *p, anyOutput *o)
+{
+	POINT pts[5];
+	LineDEF tld = {0.0, 1.0, 0x00c0c0c0, 0x0L};
+
+	if(!p || !o) return;
+	if(to) {
+		o->CopyBitmap(trc.left, trc.top, to, 0, 0, trc.right - trc.left, 
+			trc.bottom - trc.top, false);
+		DelBitmapClass(to);		to = 0L;
+		o->UpdateRect(&trc, false);
+		}
+	trc.left = pts[0].x = pts[1].x = pts[4].x = rDims.left + p->x;		
+	trc.top = pts[0].y = pts[3].y = pts[4].y = rDims.top + p->y;
+	trc.bottom = pts[1].y = pts[2].y = rDims.bottom + p->y;
+	trc.right = pts[2].x = pts[3].x = rDims.right + p->x;
+	IncrementMinMaxRect(&trc, 3);	to = GetRectBitmap(&trc, o);
+	o->SetLine(&tld);				o->oPolyline(pts, 5, 0L);
+	o->UpdateRect(&trc, false);
+} 
+
+bool
+Legend::HasFill(LineDEF *ld, FillDEF *fd, char *desc)
+{
+	int i;
+	LegItem *li;
+
+	if(Items) for(i = 0; i < nItems; i++) {
+		if(Items[i] && Items[i]->HasFill(ld, fd, desc)) return true;
+		}
+	if(li = new LegItem(this, data, 0L, ld, fd, desc)){
+		if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+		}
+	return false;
+}
+
+bool
+Legend::HasSym(LineDEF *ld, GraphObj *sy, char *desc)
+{
+	int i, sym;
+	Symbol *ns;
+	LegItem *li;
+
+	if(!parent || !sy) return true;
 	if(ld) hasLine = true;
-	if(Items) for(i = 0; i < nItems; i++) {
-		if(Items[i] && Items[i]->HasSym(ld, sy)) return true;
-		}
-	sym = sy->Id == GO_SYMBOL ? (sy->type & 0xff) : 0;
-	if(!(ns = new Symbol(this, data, 0.0, 0.0, sym | SYM_POS_PARENT))) return true;
-	ns->SetSize(SIZE_SYMBOL, sy->GetSize(SIZE_SYMBOL));
-	ns->SetSize(SIZE_SYM_LINE, sy->GetSize(SIZE_SYM_LINE));
-	ns->SetColor(COL_SYM_LINE, sy->GetColor(COL_SYM_LINE));
-	ns->SetColor(COL_SYM_FILL, sy->GetColor(COL_SYM_FILL));
-	if(li = new LegItem(this, data, ld, ns)){
-		if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
-		}
-	return false;
-}
+	if(Items) for(i = 0; i < nItems; i++) {
+		if(Items[i] && Items[i]->HasSym(ld, sy)) return true;
+		}
+	sym = sy->Id == GO_SYMBOL ? (sy->type & 0xff) : 0;
+	if(!(ns = new Symbol(this, data, 0.0, 0.0, sym | SYM_POS_PARENT))) return true;
+	ns->SetSize(SIZE_SYMBOL, sy->GetSize(SIZE_SYMBOL));
+	ns->SetSize(SIZE_SYM_LINE, sy->GetSize(SIZE_SYM_LINE));
+	ns->SetColor(COL_SYM_LINE, sy->GetColor(COL_SYM_LINE));
+	ns->SetColor(COL_SYM_FILL, sy->GetColor(COL_SYM_FILL));
+	if(desc && desc[0]) {
+		ns->name = (char*)memdup(desc,(int)strlen(desc)+1, 0); 
+		}
+	else if(sy->name && sy->name[0]) {
+		ns->name = (char*)memdup(sy->name,(int)strlen(sy->name)+1, 0); 
+		}
+	else if(sy->parent && sy->parent->name && sy->parent->name[0]) {
+		ns->name = (char*)memdup(sy->parent->name,(int)strlen(sy->parent->name)+1, 0); 
+		}
+	if(li = new LegItem(this, data, ld, ns)){
+		if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+		}
+	return false;
+}
 
 bool
 Legend::HasErr(LineDEF *ld, int err, char *desc)
@@ -7538,188 +8516,167 @@ Legend::HasErr(LineDEF *ld, int err, char *desc)
 		}
 	return false;
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Graphs are graphic objects containing plots, axes, and drawn objects
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Graph::Graph(GraphObj *par, DataObj *d, anyOutput *o):GraphObj(par, d)
-{
-	Graph::FileIO(INIT_VARS);
-	Disp = o;		Id = GO_GRAPH;		cGraphs++;	bModified = true;
-	if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
-}
-
-Graph::Graph(int src):GraphObj(0L, 0L)
-{
-	int i;
-
-	Graph::FileIO(INIT_VARS);
-	if(src == FILE_READ) {
-		FileIO(FILE_READ);
-		x_axis.owner = y_axis.owner = (void *)this;
-		//do all axes
-		for(i = 0; Axes && i< NumAxes; i++) if(Axes[i]) Axes[i]->parent = this;
-		//do all plots
-		for(i = 0; Plots && i< NumPlots; i++) if(Plots[i]) Plots[i]->parent = this;
-		if(x_axis.max > x_axis.min && y_axis.max > y_axis.min &&
-			Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) dirty = false;
-		}
-	cGraphs++;		bModified = false;
-}
-
-Graph::~Graph()
-{
-	int i;
-
-	if(!parent) return;			parent = 0L;
-	Undo.InvalidGO(this);		DoZoom("reset");
-	if(CurrGraph == this) CurrGraph = 0L;
-	if(Plots) {
-		for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
-		free(Plots);		Plots = 0L;		NumPlots = 0;
-		}
-	if(Axes) {
-		for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
-		free(Axes);			Axes = 0L;		NumAxes = 0;
-		}
-	if(OwnDisp && Disp) DelDispClass(Disp);		OwnDisp = false;	Disp = 0L;
-	if(frm_g) DeleteGO(frm_g);		if(frm_d) DeleteGO(frm_d);
-	if(x_axis.breaks && x_axis.owner == this) free(x_axis.breaks);
-	if(y_axis.breaks && y_axis.owner == this) free(y_axis.breaks);
-	if(tl_pts) free(tl_pts);
-	if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
-	nscp = 0;			Sc_Plots = 0L;
-	if(name) free(name);		name = 0L;
-	if(filename) free(filename);	filename= 0L;
-}
-
-double
-Graph::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_LB_XDIST:
-	case SIZE_LB_YDIST:			return 0.0f;
-	case SIZE_GRECT_TOP:		return GRect.Ymin;
-	case SIZE_GRECT_BOTTOM:		return GRect.Ymax;
-	case SIZE_GRECT_LEFT:		return GRect.Xmin;
-	case SIZE_GRECT_RIGHT:		return GRect.Xmax;
-	case SIZE_DRECT_TOP:		return DRect.Ymin;
-	case SIZE_DRECT_BOTTOM:		return DRect.Ymax;
-	case SIZE_DRECT_LEFT:		return DRect.Xmin;
-	case SIZE_DRECT_RIGHT:		return DRect.Xmax;
-	case SIZE_BOUNDS_XMIN:		return Bounds.Xmin;
-	case SIZE_BOUNDS_XMAX:		return Bounds.Xmax;
-	case SIZE_BOUNDS_YMIN:		return Bounds.Ymin;
-	case SIZE_BOUNDS_YMAX:		return Bounds.Ymax;
-	case SIZE_BOUNDS_LEFT:		return x_axis.flags & AXIS_INVERT ? x_axis.max : x_axis.min;
-	case SIZE_BOUNDS_RIGHT:		return x_axis.flags & AXIS_INVERT ? x_axis.min : x_axis.max;
-	case SIZE_BOUNDS_TOP:		return y_axis.flags & AXIS_INVERT ? y_axis.min : y_axis.max;
-	case SIZE_BOUNDS_BOTTOM:	return y_axis.flags & AXIS_INVERT ? y_axis.max : y_axis.min;
-	case SIZE_YAXISX:
-		if(y_axis.flags & AXIS_X_DATA) return CurrDisp->fx2fix(y_axis.loc[0].fx);
-		else return CurrDisp->co2fix(y_axis.loc[0].fx);
-	case SIZE_XAXISY:
-		if(x_axis.flags & AXIS_Y_DATA) return CurrDisp->fy2fiy(x_axis.loc[0].fy);
-		else return CurrDisp->co2fiy(x_axis.loc[0].fy);
-	default:		return defs.GetSize(select);
-		}
-}
-
-bool
-Graph::SetSize(int select, double val)
-{
-	switch(select & 0xfff) {
-	case SIZE_GRECT_TOP:	GRect.Ymin = val;	return true;
-	case SIZE_GRECT_BOTTOM:	GRect.Ymax = val;	return true;
-	case SIZE_GRECT_LEFT:	GRect.Xmin = val;	return true;
-	case SIZE_GRECT_RIGHT:	GRect.Xmax = val;	return true;
-	case SIZE_DRECT_TOP:	DRect.Ymin = val;	return true;
-	case SIZE_DRECT_BOTTOM:	DRect.Ymax = val;	return true;
-	case SIZE_DRECT_LEFT:	DRect.Xmin = val;	return true;
-	case SIZE_DRECT_RIGHT:	DRect.Xmax = val;	return true;
-	default: return false;
-		}
-}
-
-DWORD
-Graph::GetColor(int select)
-{
-	switch(select & 0xfff) {
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphs are graphic objects containing plots, axes, and drawn objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Graph::Graph(GraphObj *par, DataObj *d, anyOutput *o):GraphObj(par, d)
+{
+	Graph::FileIO(INIT_VARS);
+	Disp = o;		Id = GO_GRAPH;		cGraphs++;	bModified = true;
+	if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+Graph::Graph(int src):GraphObj(0L, 0L)
+{
+	int i;
+
+	Graph::FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		x_axis.owner = y_axis.owner = (void *)this;
+		//do all axes
+		for(i = 0; Axes && i< NumAxes; i++) if(Axes[i]) Axes[i]->parent = this;
+		//do all plots
+		for(i = 0; Plots && i< NumPlots; i++) if(Plots[i]) Plots[i]->parent = this;
+		if(x_axis.max > x_axis.min && y_axis.max > y_axis.min &&
+			Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) dirty = false;
+		}
+	cGraphs++;		bModified = false;
+}
+
+Graph::~Graph()
+{
+	int i;
+
+	if(!parent) return;			parent = 0L;
+	Undo.InvalidGO(this);		DoZoom("reset");
+	if(CurrGraph == this) CurrGraph = 0L;
+	if(Plots) {
+		for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
+		free(Plots);		Plots = 0L;		NumPlots = 0;
+		}
+	if(Axes) {
+		for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+		free(Axes);			Axes = 0L;		NumAxes = 0;
+		}
+	if(OwnDisp && Disp) DelDispClass(Disp);		OwnDisp = false;	Disp = 0L;
+	if(frm_g) DeleteGO(frm_g);		if(frm_d) DeleteGO(frm_d);
+	if(x_axis.breaks && x_axis.owner == this) free(x_axis.breaks);
+	if(y_axis.breaks && y_axis.owner == this) free(y_axis.breaks);
+	if(tl_pts) free(tl_pts);
+	if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
+	nscp = 0;			Sc_Plots = 0L;
+	if(name) free(name);		name = 0L;
+	if(filename) free(filename);	filename= 0L;
+}
+
+double
+Graph::GetSize(int select)
+{
+	return Graph::DefSize(select);
+}
+
+bool
+Graph::SetSize(int select, double val)
+{
+	switch(select & 0xfff) {
+	case SIZE_GRECT_TOP:	GRect.Ymin = val;	return true;
+	case SIZE_GRECT_BOTTOM:	GRect.Ymax = val;	return true;
+	case SIZE_GRECT_LEFT:	GRect.Xmin = val;	return true;
+	case SIZE_GRECT_RIGHT:	GRect.Xmax = val;	return true;
+	case SIZE_DRECT_TOP:	DRect.Ymin = val;	return true;
+	case SIZE_DRECT_BOTTOM:	DRect.Ymax = val;	return true;
+	case SIZE_DRECT_LEFT:	DRect.Xmin = val;	return true;
+	case SIZE_DRECT_RIGHT:	DRect.Xmax = val;	return true;
+	default: return false;
+		}
+}
+
+DWORD
+Graph::GetColor(int select)
+{
+	switch(select & 0xfff) {
 	case COL_AXIS:		return ColAX;
-	case COL_BG:		return ColDR;
-		}
-	if(parent) return parent->GetColor(select);
-	else return defs.Color(select);
-}
-
-
-void
-Graph::DoPlot(anyOutput *target)
-{
-	int i;
-	AxisDEF *ax;
-
-	if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
-	nscp = 0;		Sc_Plots = 0L;
-	rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
-	CurrAxes = Axes;
-	if(data) do_formula(data, 0L);			//init mfcalc
-	//verify ownership of axes
-	if(Axes) for (i = 0; i < NumAxes; i++){
-		if(Axes[i] && (ax = Axes[i]->GetAxis()))
-			if(ax == &x_axis || ax == &y_axis) ax->owner = this;
-		}
-	if(!name){
-		sprintf(TmpTxt, "Graph %d", cGraphs);
-		name = strdup(TmpTxt);
-		}
-	if(!target && !Disp) {
-		Disp = NewDispClass(this);
-		Disp->SetMenu(MENU_GRAPH);
-		if(name) Disp->Caption(name);
-		Disp->VPorg.fy = (double)Disp->MenuHeight;
-		Disp->CheckMenu(ToolMode, true);
-		OwnDisp = true;						defs.SetDisp(Disp);
-		if(GRect.Xmin > 0.0001 || GRect.Xmin < -0.0001) {
-			GRect.Xmax -= GRect.Xmin;	GRect.Xmin = 0.0;
-			}
-		if(GRect.Ymin > 0.0001 || GRect.Ymin < -0.0001) {
-			GRect.Ymax -= GRect.Ymin;	GRect.Ymin = 0.0;
-			}
-		bModified = false;			//first graph is not modified!
-		}
-	//the first output class is the display class
-	if(!Disp && (!(Disp = target))) return;
-	Disp->ActualSize(&defs.clipRC);
-	if(OwnDisp) Disp->Erase(Disp->dFillCol = defs.Color(COL_BG));
-	CurrDisp = target ? target : Disp;
-	CurrDisp->MrkMode = MRK_NONE;
-	CurrRect.Xmin=GRect.Xmin + DRect.Xmin;	CurrRect.Xmax=GRect.Xmin + DRect.Xmax;
-	CurrRect.Ymin=GRect.Ymin + DRect.Ymax;	CurrRect.Ymax=GRect.Ymin + DRect.Ymin;
-	if(dirty) DoAutoscale();
+	case COL_BG:		return ColDR;
+		}
+	if(parent) return parent->GetColor(select);
+	else return defs.Color(select);
+}
+
+
+void
+Graph::DoPlot(anyOutput *target)
+{
+	int i, cb;
+	AxisDEF *ax;
+
+	if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
+	nscp = 0;		Sc_Plots = 0L;
+	rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
+	CurrAxes = Axes;
+	if(data) do_formula(data, 0L);			//init mfcalc
+	//verify ownership of axes
+	if(Axes) for (i = 0; i < NumAxes; i++){
+		if(Axes[i] && (ax = Axes[i]->GetAxis()))
+			if(ax == &x_axis || ax == &y_axis) ax->owner = this;
+		}
+	if(!name){
+#ifdef USE_WIN_SECURE
+		cb = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Graph %d", cGraphs) + 2;
+#else
+		cb = sprintf(TmpTxt, "Graph %d", cGraphs) + 2;
+#endif
+		name = (char*)realloc(name, cb);		rlp_strcpy(name, cb, TmpTxt);
+		}
+	if(!target && !Disp) {
+		Disp = NewDispClass(this);
+		Disp->SetMenu(MENU_GRAPH);
+		if(name) Disp->Caption(name);
+		Disp->VPorg.fy = (double)Disp->MenuHeight;
+		Disp->CheckMenu(ToolMode, true);
+		OwnDisp = true;						defs.SetDisp(Disp);
+		if(GRect.Xmin > 0.0001 || GRect.Xmin < -0.0001) {
+			GRect.Xmax -= GRect.Xmin;	GRect.Xmin = 0.0;
+			}
+		if(GRect.Ymin > 0.0001 || GRect.Ymin < -0.0001) {
+			GRect.Ymax -= GRect.Ymin;	GRect.Ymin = 0.0;
+			}
+		bModified = false;			//first graph is not modified!
+		Undo.SetDisp(Disp);
+		}
+	//the first output class is the display class
+	if(!Disp && (!(Disp = target))) return;
+	Disp->ActualSize(&defs.clipRC);
+	if(OwnDisp) Disp->Erase(Disp->dFillCol = defs.Color(COL_BG));
+	CurrDisp = target ? target : Disp;
+	CurrDisp->MrkMode = MRK_NONE;
+	CurrRect.Xmin=GRect.Xmin + DRect.Xmin;	CurrRect.Xmax=GRect.Xmin + DRect.Xmax;
+	CurrRect.Ymin=GRect.Ymin + DRect.Ymax;	CurrRect.Ymax=GRect.Ymin + DRect.Ymin;
+	if(dirty) DoAutoscale();
 	CurrDisp->SetRect(CurrRect, units, &x_axis, &y_axis);
 	CurrDisp->disp_x = CurrDisp->un2fix(GRect.Xmin);
 	CurrDisp->disp_y = CurrDisp->un2fiy(GRect.Ymin);
-	if(!frm_g && !(frm_g = new FrmRect(this, 0L, &GRect, 0L))) return;
-	frm_g->SetColor(COL_GRECT, ColGR);	frm_g->SetColor(COL_GRECTLINE, ColGRL);
-	frm_g->DoPlot(CurrDisp);
-	if(type == GT_STANDARD) {
-		if(!frm_d && !(frm_d = new FrmRect(this, &GRect, &DRect, 0L))) return;
-		SetMinMaxRect(&rDims, CurrDisp->co2ix(CurrRect.Xmin), CurrDisp->co2iy(CurrRect.Ymax), 
-			CurrDisp->co2ix(CurrRect.Xmax), CurrDisp->co2iy(CurrRect.Ymin));
-		frm_g->Command(CMD_MINRC, &rDims, CurrDisp);
-		SetMinMaxRect(&rDims, CurrDisp->co2ix(GRect.Xmin), CurrDisp->co2iy(GRect.Ymax), 
-			CurrDisp->co2ix(GRect.Xmax), CurrDisp->co2iy(GRect.Ymin));
-		frm_d->Command(CMD_MAXRC, &rDims, CurrDisp);
-		frm_d->SetColor(COL_DRECT, ColDR);		frm_d->DoPlot(CurrDisp);
-		frm_g->Command(CMD_SETCHILD, &DRect, CurrDisp);
-		}
-	//do all axes
+	if(!frm_g && !(frm_g = new FrmRect(this, 0L, &GRect, 0L))) return;
+	frm_g->SetColor(COL_GRECT, ColGR);	frm_g->SetColor(COL_GRECTLINE, ColGRL);
+	frm_g->DoPlot(CurrDisp);
+	if(type == GT_STANDARD) {
+		if(!frm_d && !(frm_d = new FrmRect(this, &GRect, &DRect, 0L))) return;
+		SetMinMaxRect(&rDims, CurrDisp->co2ix(CurrRect.Xmin), CurrDisp->co2iy(CurrRect.Ymax), 
+			CurrDisp->co2ix(CurrRect.Xmax), CurrDisp->co2iy(CurrRect.Ymin));
+		frm_g->Command(CMD_MINRC, &rDims, CurrDisp);
+		SetMinMaxRect(&rDims, CurrDisp->co2ix(GRect.Xmin), CurrDisp->co2iy(GRect.Ymax), 
+			CurrDisp->co2ix(GRect.Xmax), CurrDisp->co2iy(GRect.Ymin));
+		frm_d->Command(CMD_MAXRC, &rDims, CurrDisp);
+		frm_d->SetColor(COL_DRECT, ColDR);		frm_d->DoPlot(CurrDisp);
+		frm_g->Command(CMD_SETCHILD, &DRect, CurrDisp);
+		}
+	//do all axes
 	if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]){
 		Axes[i]->SetColor(COL_BG, ColGR);
 		Axes[i]->DoPlot(CurrDisp);
-		}
-	//do all plots
+		}
+	//do all plots
 	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) {
 		if(Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH) {
 			if(((Plot*)Plots[i])->hidden == 0) Plots[i]->DoPlot(CurrDisp);
@@ -7728,199 +8685,212 @@ Graph::DoPlot(anyOutput *target)
 			Plots[i]->DoPlot(CurrDisp);
 			}
 		}
-	if(bModified) data->Command(CMD_MRK_DIRTY, 0L, 0L);
-	if(target && ToolMode == TM_STANDARD) target->MouseCursor(MC_ARROW, false);
-}
-
-bool
-Graph::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-	GraphObj **tmpPlots;
-	char *f_name;
-	RECT rc;
-	int i, j;
-	DWORD delflg = 0L;
-
-	if(!o) o = Disp ? Disp : CurrDisp;
-	switch (cmd){
+	if(bModified) data->Command(CMD_MRK_DIRTY, 0L, 0L);
+	if(parent && parent->Id == GO_GRAPH) {
+		parent->Command(CMD_AXIS, 0L, 0L);
+		}
+	if(target && ToolMode == TM_STANDARD) target->MouseCursor(MC_ARROW, false);
+}
+
+bool
+Graph::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+	GraphObj **tmpPlots;
+	char *f_name;
+	RECT rc;
+	int i, j;
+	DWORD delflg = 0L;
+
+	if(!o) o = Disp ? Disp : CurrDisp;
+	switch (cmd){
     case CMD_CAN_CLOSE:
 		HideTextCursor();
 		if(bModified) {
+			if (Undo.isEmpty(CurrDisp)) return true;
 			bModified = false;
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s has not been saved.\nDo you want to save it now?", name);
+#else
 			sprintf(TmpTxt, "%s has not been saved.\nDo you want to save it now?", name);
+#endif
 			i = YesNoCancelBox(TmpTxt);
 			if(i == 2) return false;
 			else if(i == 1) if(! SaveGraphAs(this)) return false;
 			}
 		return true;
+	case CMD_SCALE:
+		return DoScale((scaleINFO*)tmpl, o);
 	case CMD_LAYERS:
 		Undo.SetDisp(o ? o : CurrDisp);
 		return ShowLayers(this);
 	case CMD_HASSTACK:
 		return(NumPlots > 1);
-	case CMD_SAVEPOS:
-		Undo.ValRect(this, &GRect, 0L);
-		Undo.ValRect(this, &DRect, UNDO_CONTINUE);
-		return true;
-	case CMD_LEGEND:
+	case CMD_SAVEPOS:
+		Undo.ValRect(this, &GRect, 0L);
+		Undo.ValRect(this, &DRect, UNDO_CONTINUE);
+		return true;
+	case CMD_LEGEND:
 		Undo.SetDisp(o ? o : CurrDisp);
-		if(Id == GO_PAGE) {
+		if(Id == GO_PAGE) {
 			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
 				CurrGraph = (Graph*)Plots[0];
 				return CurrGraph->Command(cmd, tmpl, o);
-				}
-			InfoBox("No graph selected!\nCreate a new graph first or select\n"
-				"a graph before you can add a legend.");
-			return false;
-			}
-		if(Id == GO_GRAPH && !tmpl && Plots) {
-			for(i = 0; i< NumPlots; i++){
-				if(Plots[i] && Plots[i]->Id == GO_LEGEND) {
-					tmpl = (void*)Plots[i];
-					Undo.ObjConf(Plots[i], 0L);
-					break;
-					}
-				}
-			if(!tmpl) {
+				}
+			InfoBox("No graph selected!\nCreate a new graph first or select\n"
+				"a graph before you can add a legend.");
+			return false;
+			}
+		if(Id == GO_GRAPH && !tmpl && Plots) {
+			for(i = 0; i< NumPlots; i++){
+				if(Plots[i] && Plots[i]->Id == GO_LEGEND) {
+					tmpl = (void*)Plots[i];
+					Undo.ObjConf(Plots[i], 0L);
+					break;
+					}
+				}
+			if(!tmpl) {
 				if(!(tmpl = (void*) new Legend(this, data)))return false;
 				if(Disp) {
-					Undo.SetDisp(Disp);
-					tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
-					if(!tmpPlots) return false;
-					Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-					Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+					Undo.SetDisp(Disp);
+					tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
+					if(!tmpPlots) return false;
+					Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+					Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
 					free(Plots);		Plots = tmpPlots;	bModified = true;
 					}
 				else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
 					Plots[NumPlots++] = (GraphObj*)tmpl;	Plots[NumPlots] = 0L;
 					}
-				else return false;
-				}
-			if(type == GT_CIRCCHART)((Legend*)tmpl)->SetSize(SIZE_XPOS, DRect.Xmin*3.0);
-			for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
-			if(Disp) Command(CMD_REDRAW, 0L, CurrDisp);
-			}
-		return true;
-	case CMD_REPL_GO:
-		if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
-		if(Axes) for(i = 0; i < NumAxes; i++) if(Axes[i] && Axes[i] == tmpPlots[0]){
-			tmpPlots[1]->parent = this;
-			tmpPlots[1]->Command(CMD_SET_DATAOBJ, data, o);
-			Axes[i] = (Axis *)tmpPlots[1];
-			tmpPlots[0]->parent = 0L;		//disable messaging
-			//check for default axes
-			if(((Axis*)tmpPlots[0])->GetAxis() == &x_axis) {
-				if(x_axis.breaks) free(x_axis.breaks);
-				memcpy(&x_axis, Axes[i]->axis, sizeof(AxisDEF));
-				if(x_axis.owner == Axes[i]) free(Axes[i]->axis);
-				Axes[i]->axis = &x_axis;			x_axis.owner = this;
-				}
-			else if(((Axis*)tmpPlots[0])->GetAxis() == &y_axis) {
-				if(y_axis.breaks) free(y_axis.breaks);
-				memcpy(&y_axis, Axes[i]->axis, sizeof(AxisDEF));
-				if(y_axis.owner == Axes[i]) free(Axes[i]->axis);
-				Axes[i]->axis = &y_axis;			y_axis.owner = this;
-				}
-			DeleteGO(tmpPlots[0]);
-			return bModified = dirty = true;
-			}
-		if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) { 
-			return bModified = dirty = ReplaceGO((GraphObj**)&Plots[i], tmpPlots);
-			}
-		return false;
-	case CMD_MUTATE:
-		if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
-		if(Plots) for (i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) {
-			Undo.MutateGO((GraphObj**)&Plots[i], tmpPlots[1], 0L, o);
-			if(ToolMode) Command(CMD_TOOLMODE, 0L, o);
-			return bModified = true;
-			}
-		break;
-	case CMD_HIDE_MARK:
-		if(!tmpl || !o) return false;
-		//do frame rectangles
-		if(frm_g && tmpl == (void*)frm_g) {
-			frm_g->DoMark(o, false);					return true;
-			}
-		if(frm_d && tmpl == (void*)frm_d) {
-			frm_d->DoMark(o, false);					return true;
-			}
-		//do all axes
-		if(Axes)for(i = NumAxes-1; i>=0; i--) {
-			if(tmpl == (void*)Axes[i]){
-				Axes[i]->DoMark(CurrDisp, false);		return true;
-				}
-			else if(Axes[i] && Axes[i]->Id == GO_AXIS) {
-				if(Axes[i]->Command(cmd, tmpl, o))		return true;
-				}
-			}
-		//do all plots
-		if(Plots)for(i = NumPlots-1; i>=0; i--) {
-			if(tmpl == (void*)Plots[i]){
-				Plots[i]->DoMark(CurrDisp, false);		return true;
-				}
-			else if(Plots[i] && (Plots[i]->Id == GO_MLABEL || Plots[i]->Id == GO_LEGEND || 
-				(Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH))) {
-				if(Plots[i]->Command(cmd, tmpl, o))		return true;
-				}
-			}
-		return false;
-	case CMD_REDRAW:
-		if(!CurrDisp) {
-			DoPlot(CurrDisp);
-			return true;
-			}
-		if(parent && parent->Id == GO_PAGE) return parent->Command(cmd, tmpl, o);
-		if(CurrDisp && CurrDisp->Erase(ColBG)) CurrDisp->StartPage();
-		CurrDisp->MrkMode = MRK_NONE;
-		DoPlot(CurrDisp);
-		if(CurrDisp) CurrDisp->EndPage();
-		if(CurrGO && CurrGO == CurrLabel && CurrLabel->Id == GO_LABEL)
-			CurrDisp->ShowMark(CurrLabel, MRK_GODRAW);
-		return true;
-	case CMD_ZOOM:
-		return DoZoom((char*)tmpl);
-	case CMD_MOUSECURSOR:
-		if(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);	
-		return true;
-	case CMD_AXIS:			//one of the plots has changed scaling: reset
-		if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
-		return true;
-	case CMD_REG_AXISPLOT:	//notification: plot can hnadle its own axes
-		if(nscp > 0 && nscp <= NumPlots && Sc_Plots)  {
-			for(i = 0; i < nscp; i++)
-				if(Sc_Plots[i] == (GraphObj*)tmpl) return true;
-			if(tmpPlots = (GraphObj**)realloc(Sc_Plots, (nscp+1)*sizeof(GraphObj*))){
-				tmpPlots[nscp++] = (GraphObj *)tmpl;
-				Sc_Plots = tmpPlots;
-				}
-			else {		//memory allocation error
-				nscp = 0;
-				Sc_Plots = 0L;
-				}
-			}
-		else {
-			if(Sc_Plots = (GraphObj **)calloc(1, sizeof(GraphObj*))){
-				Sc_Plots[0] = (GraphObj *)tmpl;
-				nscp = 1;
-				}
-			else nscp = 0;
-			}
-		return true;
-	case CMD_BUSY:
-		if(Disp) Disp->MouseCursor(MC_WAIT, true);
-		break;
-	case CMD_UNDO:
-		Command(CMD_TOOLMODE, 0L, o);
-		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
-		Undo.Restore(true, CurrDisp);
-		if(CurrDisp) CurrDisp->MouseCursor(MC_ARROW, true);
-		return true;
-	case CMD_ADDAXIS:
-		Undo.SetDisp(o ? o : CurrDisp);		Command(CMD_TOOLMODE, 0L, o);
-		if(Id == GO_PAGE) {
+				else return false;
+				}
+			if(type == GT_CIRCCHART)((Legend*)tmpl)->SetSize(SIZE_XPOS, DRect.Xmin*3.0);
+			for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+			if(Disp) Command(CMD_REDRAW, 0L, CurrDisp);
+			}
+		else if(Id == GO_GRAPH) {
+			for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+			}
+		return true;
+	case CMD_REPL_GO:
+		if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+		if(Axes) for(i = 0; i < NumAxes; i++) if(Axes[i] && Axes[i] == tmpPlots[0]){
+			tmpPlots[1]->parent = this;
+			tmpPlots[1]->Command(CMD_SET_DATAOBJ, data, o);
+			Axes[i] = (Axis *)tmpPlots[1];
+			tmpPlots[0]->parent = 0L;		//disable messaging
+			//check for default axes
+			if(((Axis*)tmpPlots[0])->GetAxis() == &x_axis) {
+				if(x_axis.breaks) free(x_axis.breaks);
+				memcpy(&x_axis, Axes[i]->axis, sizeof(AxisDEF));
+				if(x_axis.owner == Axes[i]) free(Axes[i]->axis);
+				Axes[i]->axis = &x_axis;			x_axis.owner = this;
+				}
+			else if(((Axis*)tmpPlots[0])->GetAxis() == &y_axis) {
+				if(y_axis.breaks) free(y_axis.breaks);
+				memcpy(&y_axis, Axes[i]->axis, sizeof(AxisDEF));
+				if(y_axis.owner == Axes[i]) free(Axes[i]->axis);
+				Axes[i]->axis = &y_axis;			y_axis.owner = this;
+				}
+			DeleteGO(tmpPlots[0]);
+			return bModified = dirty = true;
+			}
+		if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) { 
+			return bModified = dirty = ReplaceGO((GraphObj**)&Plots[i], tmpPlots);
+			}
+		return false;
+	case CMD_MUTATE:
+		if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+		if(Plots) for (i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) {
+			Undo.MutateGO((GraphObj**)&Plots[i], tmpPlots[1], 0L, o);
+			if(ToolMode) Command(CMD_TOOLMODE, 0L, o);
+			return bModified = true;
+			}
+		break;
+	case CMD_HIDE_MARK:
+		if(!tmpl || !o) return false;
+		//do frame rectangles
+		if(frm_g && tmpl == (void*)frm_g) {
+			frm_g->DoMark(o, false);					return true;
+			}
+		if(frm_d && tmpl == (void*)frm_d) {
+			frm_d->DoMark(o, false);					return true;
+			}
+		//do all axes
+		if(Axes)for(i = NumAxes-1; i>=0; i--) {
+			if(tmpl == (void*)Axes[i]){
+				Axes[i]->DoMark(CurrDisp, false);		return true;
+				}
+			else if(Axes[i] && Axes[i]->Id == GO_AXIS) {
+				if(Axes[i]->Command(cmd, tmpl, o))		return true;
+				}
+			}
+		//do all plots
+		if(Plots)for(i = NumPlots-1; i>=0; i--) {
+			if(tmpl == (void*)Plots[i]){
+				Plots[i]->DoMark(CurrDisp, false);		return true;
+				}
+			else if(Plots[i] && (Plots[i]->Id == GO_MLABEL || Plots[i]->Id == GO_LEGEND || 
+				(Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH))) {
+				if(Plots[i]->Command(cmd, tmpl, o))		return true;
+				}
+			}
+		return false;
+	case CMD_REDRAW:
+		if(!CurrDisp) {
+			DoPlot(CurrDisp);
+			return true;
+			}
+		if(parent && (parent->Id == GO_PAGE || parent->Id == GO_GRAPH)) return parent->Command(cmd, tmpl, o);
+		if(CurrDisp && CurrDisp->Erase(ColBG)) CurrDisp->StartPage();
+		CurrDisp->MrkMode = MRK_NONE;			DoPlot(CurrDisp);
+		if(CurrDisp) CurrDisp->EndPage();
+		if(CurrGO == this) CurrGO = 0L;
+		if(CurrGO && CurrGO == CurrLabel && CurrLabel->Id == GO_LABEL)
+			CurrDisp->ShowMark(CurrLabel, MRK_GODRAW);
+		return true;
+	case CMD_ZOOM:
+		return DoZoom((char*)tmpl);
+	case CMD_MOUSECURSOR:
+		if(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);	
+		return true;
+	case CMD_AXIS:			//one of the plots has changed scaling: reset
+		if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
+		return true;
+	case CMD_REG_AXISPLOT:	//notification: plot can hnadle its own axes
+		if(nscp > 0 && nscp <= NumPlots && Sc_Plots)  {
+			for(i = 0; i < nscp; i++)
+				if(Sc_Plots[i] == (GraphObj*)tmpl) return true;
+			if(tmpPlots = (GraphObj**)realloc(Sc_Plots, (nscp+1)*sizeof(GraphObj*))){
+				tmpPlots[nscp++] = (GraphObj *)tmpl;
+				Sc_Plots = tmpPlots;
+				}
+			else {		//memory allocation error
+				nscp = 0;
+				Sc_Plots = 0L;
+				}
+			}
+		else {
+			if(Sc_Plots = (GraphObj **)calloc(1, sizeof(GraphObj*))){
+				Sc_Plots[0] = (GraphObj *)tmpl;
+				nscp = 1;
+				}
+			else nscp = 0;
+			}
+		return true;
+	case CMD_BUSY:
+		if(Disp) Disp->MouseCursor(MC_WAIT, true);
+		break;
+	case CMD_UNDO:
+		Command(CMD_TOOLMODE, 0L, o);
+		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
+		Undo.Restore(true, CurrDisp);
+		if(CurrDisp) CurrDisp->MouseCursor(MC_ARROW, true);
+		return true;
+	case CMD_ADDAXIS:
+		Undo.SetDisp(o ? o : CurrDisp);		Command(CMD_TOOLMODE, 0L, o);
+		if(Id == GO_PAGE) {
 			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
 				CurrGraph = (Graph*)Plots[0];
@@ -7929,200 +8899,235 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			InfoBox("No graph selected!\nCreate a new graph first or select\n"
 				"a graph before you can add an axis.");
 			return false;
-			}
-		else {
-			if(type == GT_3D && Plots){
-				for(i = 0; i < NumPlots; i++)
+			}
+		else {
+			if(type == GT_3D && Plots){
+				for(i = 0; i < NumPlots; i++)
 					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
 						|| Plots[i]->Id == GO_FITFUNC3D))
-						return Plots[i]->Command(cmd, tmpl, o); 
-				}
-			else if(AddAxis()) {
-				Command(CMD_REDRAW, tmpl, o);
-				return true;
-				}
-			}
-		return false;
-	case CMD_CONFIG:
-		Command(CMD_TOOLMODE, 0L, o);
-		return Configure();
-	case CMD_FILENAME:
-		if(tmpl) {
-			if(filename) free(filename);
-			filename=strdup((char*)tmpl);
-			}
-		break;
-	case CMD_SETNAME:
-		if(OwnDisp && CurrDisp && tmpl){
-			CurrDisp->Caption((char*)tmpl);
-			if(name) free(name);	name = strdup((char*)tmpl);
-			}
-		else return false;
-		return true;
-	case CMD_SET_DATAOBJ:
-		Id = GO_GRAPH;
-		data = (DataObj *)tmpl;
-		//do axes
-		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
-		//do all plots
-		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
-		return true;
-	case CMD_OPEN:
-		Command(CMD_TOOLMODE, 0L, o);
-		if(!parent) return false;
-		f_name = OpenGraphName(filename);
-		if(f_name && f_name[0]) {
-			if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
-			return OpenGraph(Id == GO_PAGE ? this : parent, f_name, 0L, false);
-			}
-		return true;
-	case CMD_UPDHISTORY:
-		if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
-		return true;
-	case CMD_UPDATE:
+						return Plots[i]->Command(cmd, tmpl, o); 
+				}
+			else if(AddAxis()) {
+				Command(CMD_REDRAW, tmpl, o);
+				return true;
+				}
+			}
+		return false;
+	case CMD_CONFIG:
+		Command(CMD_TOOLMODE, 0L, o);		if(CurrGO == this) CurrGO = 0L;
+		return Configure();
+	case CMD_FILENAME:
+		if(tmpl) {
+			i = (int)strlen((char*)tmpl)+2;
+			filename = (char*)realloc(filename, i );
+			rlp_strcpy(filename, i, (char*)tmpl);
+			}
+		break;
+	case CMD_SETNAME:
+		if(OwnDisp && CurrDisp && tmpl && *((char*)tmpl)){
+			CurrDisp->Caption((char*)tmpl);
+			i = (int)strlen((char*)tmpl);
+			j = name && name[0] ? (int)strlen(name) : i;
+			name = (char*)realloc(name, i > j ? i+2 : j+2);
+			rlp_strcpy(name, i+2, (char*)tmpl);
+			}
+		else return false;
+		return true;
+	case CMD_SET_DATAOBJ:
+		Id = GO_GRAPH;
+		data = (DataObj *)tmpl;
+		//do axes
+		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+		//do all plots
+		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+		return true;
+	case CMD_OPEN:
+		Command(CMD_TOOLMODE, 0L, o);
+		if(!parent) return false;
+		f_name = OpenGraphName(filename);
+		if(f_name && f_name[0]) {
+			if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
+			return OpenGraph(Id == GO_PAGE ? this : parent, f_name, 0L, false);
+			}
+		return true;
+	case CMD_UPDHISTORY:
+		if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
+		return true;
+	case CMD_UPDATE:
+		Command(CMD_TOOLMODE, 0L, o);
+		Undo.SetDisp(CurrDisp);
+		if(parent && parent->Id != GO_PAGE && parent->Id != GO_GRAPH){
+			Undo.ValInt(this, &ToolMode, 0L);		//stub, all plots have UNDO_CONTINUE
+			}
+		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
+		for(i = 0; i < NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
+		for(i = 0; Plots && i < NumPlots; i++) 
+			if(Plots[i]) Plots[i]->Command(cmd, tmpl, o);
+		dirty = bModified = true;		CurrDisp->StartPage();
+		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
+		DoPlot(CurrDisp);		CurrDisp->EndPage();		CurrGO = 0L;
+		return true;
+	case CMD_DELOBJ_CONT:
+		delflg = UNDO_CONTINUE;
+	case CMD_DELOBJ:
 		Command(CMD_TOOLMODE, 0L, o);
-		Undo.SetDisp(CurrDisp);
-		if(parent && parent->Id != GO_PAGE){
-			Undo.ValInt(this, &ToolMode, 0L);		//stub, all plots have UNDO_CONTINUE
-			}
-		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
-		for(i = 0; i < NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
-		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
-		for(i = 0; Plots && i < NumPlots; i++) 
-			if(Plots[i]) Plots[i]->Command(cmd, tmpl, o);
-		dirty = bModified = true;		CurrDisp->StartPage();
-		if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
-		DoPlot(CurrDisp);		CurrDisp->EndPage();		CurrGO = 0L;
-		return true;
-	case CMD_DELOBJ_CONT:
-		delflg = UNDO_CONTINUE;
-	case CMD_DELOBJ:
-		Command(CMD_TOOLMODE, 0L, o);
-		bModified = true;
-		if(!tmpl) return false;
-		for(i = 0; i < NumAxes; i++) if(Axes[i] && (void*)Axes[i] == tmpl){
-			if(Axes[i]->Command(CMD_CAN_CLOSE, 0L, o)) {
-				Undo.DeleteGO((GraphObj**)(&Axes[i]), delflg, o);
-				return Command(CMD_REDRAW, 0L, o);
-				}
-			else {
-				InfoBox("Axes used for scaling\ncan not be deleted.");
-				return false;
-				}
-			}
-		for(i = 0; Plots && i < NumPlots; i++) if(Plots[i] && (void*)Plots[i] == tmpl) {
-			Undo.DeleteGO(&Plots[i], delflg, o);
-			Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
-			for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
-			NumPlots = j;			//compress list of objects
-			return Command(CMD_REDRAW, NULL, o);
-			}
-		if(tmpl == (void*)frm_g && parent && parent->Id == GO_PAGE) 
-			return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
-		return false;
-	case CMD_TOOLMODE:
-		if(o && tmpl) {
-			o->CheckMenu(ToolMode & 0x0f, false);
-			o->CheckMenu(ToolMode = tmpl ? (*((int*)tmpl)) & 0x0f : TM_STANDARD, true);
-			}
-		if(tl_pts && tl_nPts) free(tl_pts);
-		tl_pts = 0L;	tl_nPts = 0;
-		if(CurrDisp) CurrDisp->MrkMode = MRK_NONE;
-		if(o) switch(ToolMode & 0x0f) {
+		bModified = true;
+		if(!tmpl) return false;
+		for(i = 0; i < NumAxes; i++) if(Axes[i] && (void*)Axes[i] == tmpl){
+			if(Axes[i]->Command(CMD_CAN_CLOSE, 0L, o)) {
+				Undo.DeleteGO((GraphObj**)(&Axes[i]), delflg, o);
+				return Command(CMD_REDRAW, 0L, o);
+				}
+			else {
+				InfoBox("Axes used for scaling\ncan not be deleted.");
+				return false;
+				}
+			}
+		for(i = 0; Plots && i < NumPlots; i++) if(Plots[i] && (void*)Plots[i] == tmpl) {
+			Undo.DeleteGO(&Plots[i], delflg, o);			HideTextCursor();
+			Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
+			for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
+			NumPlots = j;			//compress list of objects
+			return Command(CMD_REDRAW, NULL, o);
+			}
+		if(tmpl == (void*)frm_g && parent && (parent->Id == GO_PAGE || parent->Id == GO_GRAPH)) 
+			return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
+		return false;
+	case CMD_TOOLMODE:
+		if(o && tmpl) {
+			Undo.SetDisp(o);
+			o->CheckMenu(ToolMode & 0x0f, false);
+			o->CheckMenu(ToolMode = tmpl ? (*((int*)tmpl)) & 0x0f : TM_STANDARD, true);
+			}
+		if(tl_pts && tl_nPts) free(tl_pts);
+		tl_pts = 0L;	tl_nPts = 0;
+		if(CurrDisp) CurrDisp->MrkMode = MRK_NONE;
+		if(o) switch(ToolMode & 0x0f) {
 		case TM_TEXT:	
-			o->MouseCursor(MC_TEXT, false);			break;
-		case TM_DRAW:		case TM_POLYLINE:		case TM_POLYGON:
+			o->MouseCursor(MC_TEXT, false);			break;
+		case TM_DRAW:		case TM_POLYLINE:		case TM_POLYGON:
 			o->MouseCursor(MC_DRAWPEN, false);		break;
 		case TM_RECTANGLE:	
 			o->MouseCursor(MC_DRAWREC, false);		break;
 		case TM_ELLIPSE:		
 			o->MouseCursor(MC_DRAWELLY, false);		break;
-		case TM_ROUNDREC:
+		case TM_ROUNDREC:
 			o->MouseCursor(MC_DRAWRREC, false);		break;
 		case TM_ARROW:
-			o->MouseCursor(MC_CROSS, false);		break;
+			o->MouseCursor(MC_CROSS, false);		break;
 		default:
-			o->MouseCursor(MC_ARROW, true);			break;
+			o->MouseCursor(MC_ARROW, true);			break;
 			}
-		return Command(CMD_REDRAW, 0L, CurrDisp);
-	case CMD_ADDPLOT:
+		return Command(CMD_REDRAW, 0L, CurrDisp);
+	case CMD_ADDPLOT:
 		Undo.SetDisp(o ? o : CurrDisp);
-		if(Id == GO_PAGE) {
-			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+		if(Id == GO_PAGE) {
+			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
 				CurrGraph = (Graph*)Plots[0];
 				return CurrGraph->Command(cmd, tmpl, o);
 				}
-			InfoBox("No graph selected!\nCreate a new graph first or select\n"
-				"a graph before you can add a plot.");
-			return false;
-			}
-		else if(Id == GO_GRAPH) {
-			if(type == GT_3D && Plots){
-				for(i = 0; i < NumPlots; i++) { 
+			InfoBox("No graph selected!\nCreate a new graph first or select\n"
+				"a graph before you can add a plot.");
+			return false;
+			}
+		else if(Id == GO_GRAPH) {
+			if(type == GT_3D && Plots){
+				for(i = 0; i < NumPlots; i++) { 
 					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
-						|| Plots[i]->Id == GO_FITFUNC3D)) {
+						|| Plots[i]->Id == GO_FITFUNC3D)) {
 						if(Plots[i]->Command(cmd, tmpl, CurrDisp)) return Command(CMD_REDRAW, 0L, o);
 						else return false;
-						}
+						}
 					}
-				return false;
-				}
-			else return AddPlot(0x0);
-			}
-		return false;
-	case CMD_MRK_DIRTY:
-		return (dirty = true);
-	case CMD_CURRLEFT:	case CMD_CURRIGHT:	case CMD_ADDCHAR:
-	case CMD_BACKSP:	case CMD_POS_FIRST:	case CMD_POS_LAST:
+				return false;
+				}
+			else return AddPlot(0x0);
+			}
+		return false;
+	case CMD_MRK_DIRTY:
+		return (dirty = true);
+	case CMD_CURRLEFT:	case CMD_CURRIGHT:	case CMD_ADDCHAR:
+	case CMD_BACKSP:	case CMD_POS_FIRST:	case CMD_POS_LAST:
 		defs.SetDisp(o);
 		if(tmpl && *((int*)tmpl) == 27) {			//Escape
-			o->HideMark();		CurrLabel = 0L;
-			}
+			if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
+				CurrGO->DoMark(o, false);				o->MrkMode = MRK_NONE;
+				CurrGO = 0L;
+				}
+			else o->HideMark();
+			CurrLabel = 0L;								HideTextCursor();
+			}
 		if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
-		if(CurrGO && tmpl && *((int*)tmpl) == 13) {
+		if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+		else if(CurrGO && tmpl && *((int*)tmpl) == 13) {
 			CurrGO->PropertyDlg();
-			}
-	case CMD_CURRUP:	case CMD_CURRDOWN:
-		if(CurrLabel && CurrLabel == CurrGO){
-			if(CurrLabel->parent && CurrLabel->parent->Id == GO_MLABEL)
-				return CurrLabel->parent->Command(cmd, tmpl, o);
-			return true;
-			}
-	case CMD_SHIFTLEFT:	case CMD_SHIFTRIGHT:	case CMD_SHIFTUP:	case CMD_SHIFTDOWN:
-		if(Id == GO_PAGE) {
-			if(CurrGraph && CurrGraph->parent == this) 
-				return CurrGraph->Command(cmd, tmpl, o);
-			}
-		else {
-			if(type == GT_3D && Plots) {
-				for(i = 0; i < NumPlots; i++) {
+			}
+	case CMD_CURRUP:	case CMD_CURRDOWN:
+		if(CurrLabel && CurrLabel == CurrGO){
+			if(CurrLabel->parent && CurrLabel->parent->Id == GO_MLABEL)
+				return CurrLabel->parent->Command(cmd, tmpl, o);
+			return true;
+			}
+		else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+	case CMD_SHIFTLEFT:	case CMD_SHIFTRIGHT:	case CMD_SHIFTUP:	case CMD_SHIFTDOWN:
+		if(Id == GO_PAGE || (CurrGraph && CurrGraph->parent == this)) {
+			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+			else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+			}
+		else {
+			if(type == GT_3D && Plots) {
+				for(i = 0; i < NumPlots; i++) {
 					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
-						|| Plots[i]->Id == GO_FITFUNC3D))
-						return Plots[i]->Command(cmd, tmpl, CurrDisp);
-					}
-				}
-			}
-		return false;
-	case CMD_MOVE_TOP:	case CMD_MOVE_UP:
-	case CMD_MOVE_DOWN:	case CMD_MOVE_BOTTOM:
-		Undo.StoreListGO(this, &Plots, &NumPlots, 0L);
-		if(MoveObj(cmd, (GraphObj *)tmpl)){
-			bModified = true;
-			CurrDisp->StartPage();			DoPlot(CurrDisp);
-			CurrDisp->EndPage();			return true;
-			}
-		return false;
-	case CMD_DELETE:
-		if(!CurrGO) return false;
-		bModified = true;
+						|| Plots[i]->Id == GO_FITFUNC3D))
+						return Plots[i]->Command(cmd, tmpl, CurrDisp);
+					}
+				}
+			else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+			}
+		return false;
+	case CMD_MOVE_TOP:	case CMD_MOVE_UP:
+	case CMD_MOVE_DOWN:	case CMD_MOVE_BOTTOM:
+		Undo.StoreListGO(this, &Plots, &NumPlots, 0L);
+		if(MoveObj(cmd, (GraphObj *)tmpl)){
+			bModified = true;
+			CurrDisp->StartPage();			DoPlot(CurrDisp);
+			CurrDisp->EndPage();			return true;
+			}
+		return false;
+	case CMD_DELETE:
+		if(!CurrGO) return false;			bModified = true;
+		if(CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
 		if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
-		if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
+		if(CurrGO->Id == GO_FRAMERECT) if(!(CurrGO = CurrGO->parent))return false;
+		if(CurrGO->parent == this) return Command(CMD_DELOBJ, (void*)CurrGO, o);
+		if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
 		return false;
 	case CMD_DROP_GRAPH:
-		if(parent) return parent->Command(cmd, tmpl, o);
-		return false;
-	case CMD_DROP_PLOT:
+		if(Disp) {
+			if(!(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2)*sizeof(GraphObj*), 0))) 
+				return false;
+			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+			free(Plots);			Plots = tmpPlots;	Plots[NumPlots] = Plots[NumPlots+1] = 0L;
+			Undo.SetGO(this, &Plots[NumPlots], (GraphObj*)tmpl, 0L);
+			}
+		else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+			Plots[NumPlots] = (GraphObj*)tmpl;	Plots[NumPlots+1] = 0L;
+			}
+		else return false;
+		if(Plots[NumPlots]){
+			Plots[NumPlots]->parent = this;
+			Plots[NumPlots]->Command(CMD_SET_DATAOBJ, data, 0L);
+			if(Plots[NumPlots]->Id == GO_GRAPH) CurrGraph = (Graph*)Plots[NumPlots];
+			Plots[NumPlots]->moveable = 1;		//all page items should be freely
+			}									//   moveable by user
+		NumPlots++;
+		if(CurrDisp) {
+			CurrDisp->StartPage();		DoPlot(CurrDisp);		CurrDisp->EndPage();
+			}
+		return true;
+	case CMD_DROP_PLOT:
 		if(!tmpl) return false;
 		((GraphObj*)tmpl)->parent = this;
 		if(((GraphObj*)tmpl)->Id < GO_PLOT) {
@@ -8136,186 +9141,195 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 				CurrDisp->EndPage();
 				}
 			return true;
-			}
-		if(Id == GO_GRAPH) CurrGraph = this;	bModified =true;
-		if(!NumPlots) {
-			Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
-			if(Plots) {
-				Plots[0] = (Plot *)tmpl;	Plots[0]->parent = this;
-				switch(Plots[0]->Id) {
-				case GO_PIECHART:		case GO_RINGCHART:	case GO_STARCHART:
-					type = GT_CIRCCHART;
-					break;
-				case GO_POLARPLOT:
-					type = GT_POLARPLOT;
-					break;
+			}
+		if(Id == GO_GRAPH) CurrGraph = this;	bModified =true;
+		if(!NumPlots) {
+			Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
+			if(Plots) {
+				Plots[0] = (Plot *)tmpl;	Plots[0]->parent = this;
+				switch(Plots[0]->Id) {
+				case GO_PIECHART:		case GO_RINGCHART:	case GO_STARCHART:
+					type = GT_CIRCCHART;
+					break;
+				case GO_POLARPLOT:
+					type = GT_POLARPLOT;
+					break;
 				case GO_SCATT3D:		case GO_PLOT3D:		case GO_FUNC3D:
-				case GO_FITFUNC3D:
-					type = GT_3D;
-					break;
-				default:
-					type = GT_STANDARD;
-					break;
-					}
-				Bounds.Xmin = x_axis.min = ((Plot*)Plots[0])->Bounds.Xmin;
-				Bounds.Xmax = x_axis.max = ((Plot*)Plots[0])->Bounds.Xmax;
-				Bounds.Ymin = y_axis.min = ((Plot*)Plots[0])->Bounds.Ymin;
-				Bounds.Ymax = y_axis.max = ((Plot*)Plots[0])->Bounds.Ymax;
-				if(Bounds.Ymax == Bounds.Ymin) {
-					if(Bounds.Ymax != 0.0f) {
-						Bounds.Ymax = y_axis.max = Bounds.Ymax + (Bounds.Ymax)/10.0f;
-						Bounds.Ymin = y_axis.min = Bounds.Ymin - (Bounds.Ymax)/10.0f;
-						}
-					else {
-						Bounds.Ymax = y_axis.max = 1.0f;
-						Bounds.Ymin = y_axis.min = -1.0f;
-						}
-					}
-				if(Bounds.Xmax == Bounds.Xmin) {
-					if(Bounds.Xmax != 0.0f) {
-						Bounds.Xmax = x_axis.max = Bounds.Xmax + (Bounds.Xmax)/10.0f;
-						Bounds.Xmin = x_axis.min = Bounds.Xmin - (Bounds.Xmax)/10.0f;
-						}
-					else {
-						Bounds.Xmax = 1.0f;
-						Bounds.Xmin = -1.0f;
-						}
-					}
-				NiceAxis(&x_axis, 4);				NiceAxis(&y_axis, 4);
-				NumPlots = 1;
-				if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
-				dirty = false;
-				return true;
-				}
-			return false;
-			}
+				case GO_FITFUNC3D:
+					type = GT_3D;
+					break;
+				default:
+					type = GT_STANDARD;
+					break;
+					}
+				Bounds.Xmin = x_axis.min = ((Plot*)Plots[0])->Bounds.Xmin;
+				Bounds.Xmax = x_axis.max = ((Plot*)Plots[0])->Bounds.Xmax;
+				Bounds.Ymin = y_axis.min = ((Plot*)Plots[0])->Bounds.Ymin;
+				Bounds.Ymax = y_axis.max = ((Plot*)Plots[0])->Bounds.Ymax;
+				if(Bounds.Ymax == Bounds.Ymin) {
+					if(Bounds.Ymax != 0.0f) {
+						Bounds.Ymax = y_axis.max = Bounds.Ymax + (Bounds.Ymax)/10.0f;
+						Bounds.Ymin = y_axis.min = Bounds.Ymin - (Bounds.Ymax)/10.0f;
+						}
+					else {
+						Bounds.Ymax = y_axis.max = 1.0f;
+						Bounds.Ymin = y_axis.min = -1.0f;
+						}
+					}
+				if(Bounds.Xmax == Bounds.Xmin) {
+					if(Bounds.Xmax != 0.0f) {
+						Bounds.Xmax = x_axis.max = Bounds.Xmax + (Bounds.Xmax)/10.0f;
+						Bounds.Xmin = x_axis.min = Bounds.Xmin - (Bounds.Xmax)/10.0f;
+						}
+					else {
+						Bounds.Xmax = 1.0f;
+						Bounds.Xmin = -1.0f;
+						}
+					}
+				NiceAxis(&x_axis, 4);				NiceAxis(&y_axis, 4);
+				NumPlots = 1;
+				if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
+				dirty = false;
+				return true;
+				}
+			return false;
+			}
 		else {
 			if(Disp) {
-				Undo.SetDisp(Disp);
+				Undo.SetDisp(Disp);
 				tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
-				Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-				Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+				Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+				Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
 				free(Plots);			Plots = tmpPlots;
 				}
 			else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
 				Plots[NumPlots++] = (Plot*)tmpl;	Plots[NumPlots] = 0L;
 				}
 			else return false;
-			if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) || 
-				(y_axis.flags & AXIS_AUTOSCALE))) {
-				if(x_axis.flags & AXIS_AUTOSCALE) {
-					Bounds.Xmin = x_axis.min = ((Plot *)tmpl)->Bounds.Xmin < Bounds.Xmin ?
-						((Plot *)tmpl)->Bounds.Xmin : Bounds.Xmin;
-					Bounds.Xmax = x_axis.max = ((Plot *)tmpl)->Bounds.Xmax > Bounds.Xmax ?
-						((Plot *)tmpl)->Bounds.Xmax : Bounds.Xmax;
-					NiceAxis(&x_axis, 4);
-					if(Axes)for(i = 0; i < NumAxes; i++) 
-						if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, o);
-					}
-				if(y_axis.flags & AXIS_AUTOSCALE) {
-					Bounds.Ymin = y_axis.min = ((Plot *)tmpl)->Bounds.Ymin < Bounds.Ymin ? 
-						((Plot *)tmpl)->Bounds.Ymin : Bounds.Ymin;
-					Bounds.Ymax = y_axis.max = ((Plot *)tmpl)->Bounds.Ymax > Bounds.Ymax ?
-						((Plot *)tmpl)->Bounds.Ymax : Bounds.Ymax;
-					NiceAxis(&y_axis, 4);
-					if(Axes)for(i = 0; i < NumAxes; i++) 
-						if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, o);
-					}
-				}
-			dirty = false;
+			if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) || 
+				(y_axis.flags & AXIS_AUTOSCALE))) {
+				if(x_axis.flags & AXIS_AUTOSCALE) {
+					Bounds.Xmin = x_axis.min = ((Plot *)tmpl)->Bounds.Xmin < Bounds.Xmin ?
+						((Plot *)tmpl)->Bounds.Xmin : Bounds.Xmin;
+					Bounds.Xmax = x_axis.max = ((Plot *)tmpl)->Bounds.Xmax > Bounds.Xmax ?
+						((Plot *)tmpl)->Bounds.Xmax : Bounds.Xmax;
+					NiceAxis(&x_axis, 4);
+					if(Axes)for(i = 0; i < NumAxes; i++) 
+						if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, o);
+					}
+				if(y_axis.flags & AXIS_AUTOSCALE) {
+					Bounds.Ymin = y_axis.min = ((Plot *)tmpl)->Bounds.Ymin < Bounds.Ymin ? 
+						((Plot *)tmpl)->Bounds.Ymin : Bounds.Ymin;
+					Bounds.Ymax = y_axis.max = ((Plot *)tmpl)->Bounds.Ymax > Bounds.Ymax ?
+						((Plot *)tmpl)->Bounds.Ymax : Bounds.Ymax;
+					NiceAxis(&y_axis, 4);
+					if(Axes)for(i = 0; i < NumAxes; i++) 
+						if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, o);
+					}
+				}
+			dirty = false;
 			//Redraw graph to show all plots
-			if(CurrDisp) {
-				CurrDisp->StartPage();
-				DoPlot(CurrDisp);
+			if(CurrDisp) {
+				CurrDisp->StartPage();
+				DoPlot(CurrDisp);
 				CurrDisp->EndPage();
-				}
-			return true;
-			}
+				}
+			return true;
+			}
 		break;
 	case CMD_PASTE_OBJ:
-//		ToolMode = TM_PASTE;			o->MouseCursor(MC_PASTE, false);
-//		PasteObj = (GraphObj*)tmpl;
-		return false;
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *)tmpl;		defs.SetDisp(o);
-		if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
-			(TrackGO = (GraphObj*)CurrGO->ObjThere(mev->x, mev->y))){
-			ToolMode |= TM_MOVE;
-			}
-		else if(mev->Action == MOUSE_LBDOWN){
-			CurrGO = 0L;
-			if((ToolMode & 0xff) == TM_STANDARD || (ToolMode & 0xff) == TM_ZOOMIN){
-				rc_mrk.left = mev->x;		rc_mrk.top = mev->y;
-				}
-			}
-		if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
-		switch(mev->Action) {
-		case MOUSE_RBUP:
+		if(!tmpl) return false;
+		Undo.SetDisp(o ? o : CurrDisp);
+		PasteObj = (GraphObj*)tmpl;
+		if(PasteObj->Id == GO_GRAPH) {
+			ToolMode = TM_PASTE;			o->MouseCursor(MC_PASTE, false);
+			return true;
+			}
+		PasteObj = 0L;
+		return false;
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *)tmpl;		defs.SetDisp(o);
+		if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
+			(TrackGO = (GraphObj*)CurrGO->ObjThere(mev->x, mev->y))){
+			ToolMode |= TM_MOVE;
+			}
+		else if(mev->Action == MOUSE_LBDOWN){
+			if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(cmd, tmpl, o)) return true;
+			CurrGO = 0L;
+			if((ToolMode & 0xff) == TM_STANDARD || (ToolMode & 0xff) == TM_ZOOMIN){
+				rc_mrk.left = mev->x;		rc_mrk.top = mev->y;
+				}
+			}
+		if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
+		switch(mev->Action) {
+		case MOUSE_RBUP:
 			Undo.SetDisp(o);
-			i = ToolMode;
-			ToolMode = TM_STANDARD;
-			mev->Action = MOUSE_LBUP;	//fake select
-			Command(cmd, tmpl, o);
-			ToolMode = i;
-			//the default behaviour for right button click is the same as for
-			//   double click: execute properties dialog, just continue.
+			i = ToolMode;
+			ToolMode = TM_STANDARD;
+			mev->Action = MOUSE_LBUP;				//fake select
+			Command(cmd, tmpl, o);					ToolMode = i;
+			if(!CurrGO) CurrGO = this;
+			//the default behaviour for right button click is the same as for
+			//   double click: execute properties dialog, just continue.
 		case MOUSE_LBDOUBLECLICK:
-			if(!CurrGO){
-				mev->Action = MOUSE_LBUP;
-				Command(CMD_MOUSE_EVENT, mev, CurrDisp);
-				mev->Action = MOUSE_LBDOUBLECLICK;
-				}
+			if(!CurrGO){
+				mev->Action = MOUSE_LBUP;
+				Command(CMD_MOUSE_EVENT, mev, CurrDisp);
+				mev->Action = MOUSE_LBDOUBLECLICK;
+				if(!CurrGO) CurrGO = this;
+				if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
+				}
 			else if(CurrGO->Id < GO_PLOT) {
-				if(CurrGO->PropertyDlg()) {
-					bModified = true;
+				if(CurrGO->PropertyDlg()) {
+					bModified = true;
 					return Command(CMD_REDRAW, 0L, o);
 					}
 				}
 			else if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
-			else if (Id == GO_PAGE) return Command(CMD_CONFIG, 0L, o);
-			else o->HideMark();
-			TrackGO = 0L;	CurrLabel = 0L;
-			return false;
-		case MOUSE_LBUP:
+			else o->HideMark();
+			TrackGO = 0L;	CurrLabel = 0L;
+			if(CurrGO == this) CurrGO = 0L;
+			return false;
+		case MOUSE_LBUP:
 			Undo.SetDisp(o);
-			if(Id == GO_GRAPH){
-				CurrGO = TrackGO = 0L;
-				CurrGraph = this;
-				}
-		case MOUSE_MOVE:
-			if(mev->Action == MOUSE_MOVE && !(mev->StateFlags & 0x01)) return false;
-			//do all axes
-			for(i = 0; Axes && i< NumAxes; i++)
-				if(Axes[i] && Axes[i]->Command(cmd, tmpl,o)) return true;
-			//do all plots
-			if(Plots)for(i = NumPlots-1; i>=0; i--)
-				if(Plots[i] && Plots[i]->Command(cmd, tmpl,o)) return true;
-			if(frm_d && frm_d->Command(cmd, tmpl, o)) return true;
-			if(frm_g && frm_g->Command(cmd, tmpl, o)) return true;
-			if(mev->Action == MOUSE_MOVE && ToolMode == TM_STANDARD &&
-				rc_mrk.left >=0 && rc_mrk.top >=0) ToolMode = TM_MARK;
-			if(!CurrGO) CurrGraph = 0L;
-			return false;
-			}
-		break;
-	case CMD_SETSCROLL:
-		if(o) {
-			o->ActualSize(&rc);
-			i = o->un2iy(GRect.Ymax);
-			o->SetScroll(true, -(i>>3), i+(i>>3), (rc.bottom -rc.top)>>1, - iround(o->VPorg.fy));
-			i = o->un2ix(GRect.Xmax);
-			o->SetScroll(false, -(i>>3), i+(i>>3), (rc.right -rc.left)>>1, - iround(o->VPorg.fx));
-			if(CurrDisp && o->Erase(ColBG)) Command(CMD_REDRAW, 0L, o);
-			return true;
-			}
-		return false;
-	case CMD_SETHPOS:
-		if(o && tmpl) o->VPorg.fx = - (double)(*((int*)tmpl));
-		return Command(CMD_SETSCROLL, tmpl, o);
-	case CMD_SETVPOS:
-		if(o && tmpl) o->VPorg.fy = - (double)(*((int*)tmpl));
+			if(Id == GO_GRAPH){
+				CurrGO = TrackGO = 0L;
+				CurrGraph = this;
+				}
+		case MOUSE_MOVE:
+			if(mev->Action == MOUSE_MOVE && !(mev->StateFlags & 0x01)) return false;
+			//do all axes
+			for(i = 0; Axes && i< NumAxes; i++)
+				if(Axes[i] && Axes[i]->Command(cmd, tmpl,o)) return true;
+			//do all plots
+			if(Plots)for(i = NumPlots-1; i>=0; i--)
+				if(Plots[i] && Plots[i]->Command(cmd, tmpl,o)) return true;
+			if(frm_d && frm_d->Command(cmd, tmpl, o)) return true;
+			if(frm_g && frm_g->Command(cmd, tmpl, o)) return true;
+			if(mev->Action == MOUSE_MOVE && ToolMode == TM_STANDARD &&
+				rc_mrk.left >=0 && rc_mrk.top >=0) ToolMode = TM_MARK;
+			if(!CurrGO) CurrGraph = 0L;
+			return false;
+			}
+		break;
+	case CMD_SETSCROLL:
+		if(o) {
+			o->ActualSize(&rc);
+			i = o->un2iy(GRect.Ymax);
+			o->SetScroll(true, -(i>>3), i+(i>>3), (rc.bottom -rc.top)>>1, - iround(o->VPorg.fy));
+			i = o->un2ix(GRect.Xmax);
+			o->SetScroll(false, -(i>>3), i+(i>>3), (rc.right -rc.left)>>1, - iround(o->VPorg.fx));
+			if(CurrDisp && o->Erase(ColBG)) Command(CMD_REDRAW, 0L, o);
+			return true;
+			}
+		return false;
+	case CMD_SETHPOS:
+		if(o && tmpl) o->VPorg.fx = - (double)(*((int*)tmpl));
+		return Command(CMD_SETSCROLL, tmpl, o);
+	case CMD_SETVPOS:
+		if(o && tmpl) o->VPorg.fy = - (double)(*((int*)tmpl));
 		return Command(CMD_SETSCROLL, tmpl, o);
-	case CMD_OBJTREE:
+	case CMD_OBJTREE:
 		for(i = 0; Plots && i < NumPlots; i++) if(Plots[i]) {
 			((ObjTree*)tmpl)->Command(CMD_UPDATE, Plots[i], 0L);
 			if(Plots[i]->Id == GO_STACKBAR || Plots[i]->Id == GO_GRAPH || 
@@ -8324,480 +9338,522 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 				Plots[i]->Command(cmd, tmpl, o);
 			}
 		return true;
-		}
-	return false;
-}
-
-void
-Graph::DoAutoscale()
-{
-	int i;
-	fRECT oB;
-
-	memcpy(&oB, &Bounds, sizeof(fRECT));
-	if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) ||
-		(y_axis.flags & AXIS_AUTOSCALE))) {
-		for(i = 0; i < NumPlots; i++) {
-			if(Plots[i] && (Plots[i]->Id == GO_PLOTSCATT || Plots[i]->Id == GO_BUBBLEPLOT ||
-				Plots[i]->Id == GO_BOXPLOT || Plots[i]->Id == GO_STACKBAR ||
-				Plots[i]->Id == GO_STACKPG || Plots[i]->Id == GO_DENSDISP ||
-				Plots[i]->Id == GO_LIMITS || Plots[i]->Id == GO_FUNCTION ||
-				Plots[i]->Id == GO_FITFUNC || Plots[i]->Id== GO_FREQDIST)) {
-				bModified = true;
-				if(dirty) {
-					if(x_axis.flags & AXIS_AUTOSCALE) {
-						Bounds.Xmin = HUGE_VAL;			Bounds.Xmax = -HUGE_VAL;
-						}
-					if(y_axis.flags & AXIS_AUTOSCALE) {
-						Bounds.Ymin = HUGE_VAL;			Bounds.Ymax = -HUGE_VAL;
-						}
-					dirty = false;
-					}
+		}
+	return false;
+}
+
+double 
+Graph::DefSize(int select)
+{
+	switch(select) {
+	case SIZE_LB_XDIST:
+	case SIZE_LB_YDIST:			return 0.0f;
+	case SIZE_GRECT_TOP:		return GRect.Ymin;
+	case SIZE_GRECT_BOTTOM:		return GRect.Ymax;
+	case SIZE_GRECT_LEFT:		return GRect.Xmin;
+	case SIZE_GRECT_RIGHT:		return GRect.Xmax;
+	case SIZE_DRECT_TOP:		return DRect.Ymin;
+	case SIZE_DRECT_BOTTOM:		return DRect.Ymax;
+	case SIZE_DRECT_LEFT:		return DRect.Xmin;
+	case SIZE_DRECT_RIGHT:		return DRect.Xmax;
+	case SIZE_BOUNDS_XMIN:		return Bounds.Xmin;
+	case SIZE_BOUNDS_XMAX:		return Bounds.Xmax;
+	case SIZE_BOUNDS_YMIN:		return Bounds.Ymin;
+	case SIZE_BOUNDS_YMAX:		return Bounds.Ymax;
+	case SIZE_BOUNDS_LEFT:		return x_axis.flags & AXIS_INVERT ? x_axis.max : x_axis.min;
+	case SIZE_BOUNDS_RIGHT:		return x_axis.flags & AXIS_INVERT ? x_axis.min : x_axis.max;
+	case SIZE_BOUNDS_TOP:		return y_axis.flags & AXIS_INVERT ? y_axis.min : y_axis.max;
+	case SIZE_BOUNDS_BOTTOM:	return y_axis.flags & AXIS_INVERT ? y_axis.max : y_axis.min;
+	case SIZE_YAXISX:
+		if(y_axis.flags & AXIS_X_DATA) return CurrDisp->fx2fix(y_axis.loc[0].fx);
+		else return CurrDisp->co2fix(y_axis.loc[0].fx);
+	case SIZE_XAXISY:
+		if(x_axis.flags & AXIS_Y_DATA) return CurrDisp->fy2fiy(x_axis.loc[0].fy);
+		else return CurrDisp->co2fiy(x_axis.loc[0].fy);
+		}
+	if(scale > 0.0) return scale * defs.GetSize(select);
+	else return defs.GetSize(select);
+}
+
+void
+Graph::DoAutoscale()
+{
+	int i;
+	fRECT oB;
+
+	memcpy(&oB, &Bounds, sizeof(fRECT));
+	if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) ||
+		(y_axis.flags & AXIS_AUTOSCALE))) {
+		for(i = 0; i < NumPlots; i++) {
+			if(Plots[i] && (Plots[i]->Id == GO_PLOTSCATT || Plots[i]->Id == GO_BUBBLEPLOT ||
+				Plots[i]->Id == GO_BOXPLOT || Plots[i]->Id == GO_STACKBAR ||
+				Plots[i]->Id == GO_STACKPG || Plots[i]->Id == GO_DENSDISP ||
+				Plots[i]->Id == GO_LIMITS || Plots[i]->Id == GO_FUNCTION ||
+				Plots[i]->Id == GO_FITFUNC || Plots[i]->Id== GO_FREQDIST)) {
+				bModified = true;
+				if(dirty) {
+					if(x_axis.flags & AXIS_AUTOSCALE) {
+						Bounds.Xmin = HUGE_VAL;			Bounds.Xmax = -HUGE_VAL;
+						}
+					if(y_axis.flags & AXIS_AUTOSCALE) {
+						Bounds.Ymin = HUGE_VAL;			Bounds.Ymax = -HUGE_VAL;
+						}
+					dirty = false;
+					}
 				Plots[i]->Command(CMD_AUTOSCALE, 0L, CurrDisp);
-				if(!((Plot*)Plots[i])->hidden) {
-					if(x_axis.flags & AXIS_AUTOSCALE) {
-						Bounds.Xmin = ((Plot*)Plots[i])->Bounds.Xmin < Bounds.Xmin ?
-							((Plot*)Plots[i])->Bounds.Xmin : Bounds.Xmin;
-						Bounds.Xmax = ((Plot*)Plots[i])->Bounds.Xmax > Bounds.Xmax ?
-							((Plot*)Plots[i])->Bounds.Xmax : Bounds.Xmax;
-						}
-					if(y_axis.flags & AXIS_AUTOSCALE) {
-						Bounds.Ymin = ((Plot*)Plots[i])->Bounds.Ymin < Bounds.Ymin ?
-							((Plot*)Plots[i])->Bounds.Ymin : Bounds.Ymin;
-						Bounds.Ymax = ((Plot*)Plots[i])->Bounds.Ymax > Bounds.Ymax ?
-							((Plot*)Plots[i])->Bounds.Ymax : Bounds.Ymax;
-						}
-					}
-				}
-			}
-		if(Bounds.Xmax <= Bounds.Xmin) {
-			Bounds.Xmax = oB.Xmax > oB.Xmin ? oB.Xmax : oB.Xmax + 1.0;
-			Bounds.Xmin = oB.Xmin < oB.Xmax ? oB.Xmin : oB.Xmin - 1.0;
-			}
-		if(Bounds.Ymax <= Bounds.Ymin) {
-			Bounds.Ymax = oB.Ymax > oB.Ymin ? oB.Ymax : oB.Ymax + 1.0;
-			Bounds.Ymin = oB.Ymin < oB.Ymax ? oB.Ymin : oB.Ymin - 1.0;
-			}
-		if(x_axis.flags & AXIS_AUTOSCALE){
-			x_axis.min = Bounds.Xmin;	x_axis.max = Bounds.Xmax;
-			NiceAxis(&x_axis, 4);
-			if(x_axis.min <= 0.0 && ((x_axis.flags & 0xf000) == AXIS_LOG ||
-				(x_axis.flags & 0xf000) == AXIS_RECI)) {
-				x_axis.min = base4log(&x_axis, 0);
-				}
-			if(Axes)for(i = 0; i < NumAxes; i++)
-				if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, 0L);
-			}
-		if(y_axis.flags & AXIS_AUTOSCALE){
-			y_axis.min = Bounds.Ymin;	y_axis.max = Bounds.Ymax;
-			NiceAxis(&y_axis, 4);
-			if(y_axis.min <= 0.0 && ((y_axis.flags & 0xf000) == AXIS_LOG ||
-				(y_axis.flags & 0xf000) == AXIS_RECI)) {
-				y_axis.min = base4log(&y_axis, 1);
-				}
-			if(Axes)for(i = 0; i < NumAxes; i++)
-				if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, 0L);
-			}
-		}
-	dirty = false;
-}
-
-void
-Graph::CreateAxes(int templ)
-{
-	AxisDEF tmp_axis;
-	TextDEF label_def, tlbdef;
-	char label_text[500];
-	Label *label;
-	double ts, lb_ydist, lb_xdist, tlb_dist;
-	DWORD ptick, ntick, utick;
-
-	if(Axes && NumAxes) return;
-	label_def.ColTxt = defs.Color(COL_AXIS);
-	label_def.ColBg = 0x00ffffffL;
-	label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2;
-	label_def.RotBL = label_def.RotCHAR = 0.0;
-	label_def.iSize = 0;
-	label_def.Align = TXA_VTOP | TXA_HCENTER;
-	label_def.Mode = TXM_TRANSPARENT;
-	label_def.Style = TXS_NORMAL;
-	label_def.Font = FONT_HELVETICA;
-	label_def.text = label_text;
-	tlbdef.ColTxt = defs.Color(COL_AXIS);
-	tlbdef.ColBg = 0x00ffffffL;
-	tlbdef.RotBL = tlbdef.RotCHAR = 0.0;
-	tlbdef.iSize = 0;
-	tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
-	tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
-	tlbdef.Style = TXS_NORMAL;
-	tlbdef.Mode = TXM_TRANSPARENT;
-	tlbdef.Font = FONT_HELVETICA;
-	tlbdef.text = 0L;
-	ts = defs.GetSize(SIZE_AXIS_TICKS);
-	switch (tickstyle & 0x07){
-	case 1:						//ticks inside
-		ntick = AXIS_POSTICKS;		ptick = AXIS_POSTICKS;	utick = AXIS_NEGTICKS;
-		ts *= 0.5;
-		break;
-	case 2:						//centered, symetrical
-		ptick = ntick = utick = AXIS_SYMTICKS;
-		ts *= 0.75;
-		break;
-	default:					//ticks outside
-		ptick = AXIS_NEGTICKS;		ntick = AXIS_NEGTICKS; utick = AXIS_POSTICKS;
-		break;
-		}
-	tlb_dist = NiceValue(ts * 2.0);
-	lb_ydist = NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*2.0);
-	lb_xdist = NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0);
-	switch(templ) {
-	case 0:
-		Axes = (Axis**)calloc(5, sizeof(Axis *));
-		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
-		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;;
-		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
-			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
-			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
-			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
-			strcpy(label_text, "x-axis");
-			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
-				GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
-			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
-			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
-			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
-			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
-			strcpy(label_text, "y-axis");
-			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
-			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0, 
-				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
-			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		label = 0L;
-		memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
-		tmp_axis.owner = NULL;
-		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		if((Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK))){
-			Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist); 
-			Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist); 
-			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
-			Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
-		tmp_axis.owner = NULL;
-		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		if((Axes[3] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK))){
-			Axes[3]->SetSize(SIZE_LB_XDIST, lb_xdist); 
-			Axes[3]->SetSize(SIZE_TLB_XDIST, tlb_dist); 
-			tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
-			Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		NumAxes = 4;
-		break;
-	case 1:
-		Axes = (Axis**)calloc(7, sizeof(Axis *));
-		if(x_axis.Start >= 0.0f) x_axis.min = x_axis.Start = -x_axis.Step;
-		if(y_axis.Start >= 0.0f) y_axis.min = y_axis.Start = -y_axis.Step;
-		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
-		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		x_axis.loc[0].fy = x_axis.loc[1].fy = 0.0f;
-		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
-		if((Axes[0] = new Axis(this, data, &x_axis, ptick | AXIS_Y_DATA |	
-			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
-			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
-			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
-			strcpy(label_text, "x-axis");
-			label_def.Align = TXA_VTOP | TXA_HRIGHT;
-			label = new Label(Axes[0], data, GRect.Xmin + DRect.Xmax - defs.GetSize(SIZE_AXIS_TICKS)*2.0, 
-				GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
-			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
-			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
-			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
-			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
-			strcpy(label_text, "y-axis");
-			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HRIGHT;
-			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0, 
-				GRect.Ymin + DRect.Ymin + defs.GetSize(SIZE_AXIS_TICKS)*2.0, 
-				&label_def, LB_X_PARENT);
-			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
-		tmp_axis.owner = NULL;
-		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		if(Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK)){
-			Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist); 
-			Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
-			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
-			Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
-		if(Axes[3] = new Axis(this, data, &tmp_axis, AXIS_BOTTOM | AXIS_NOTICKS | AXIS_AUTOTICK)){
-			Axes[3]->SetSize(SIZE_LB_YDIST, lb_xdist); 
-			Axes[3]->SetSize(SIZE_TLB_YDIST, tlb_dist); 
-			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
-			Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
-		tmp_axis.owner = NULL;
-		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
-		if(Axes[4] = new Axis(this, data, &tmp_axis, AXIS_LEFT | AXIS_NOTICKS | AXIS_AUTOTICK)){
-			Axes[4]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[4]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[4]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		if(Axes[5] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK)){
-			Axes[5]->SetSize(SIZE_LB_XDIST, lb_xdist); 
-			Axes[5]->SetSize(SIZE_TLB_XDIST, tlb_dist); 
-			tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
-			Axes[5]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		NumAxes = 6;
-		break;
-	case 2:
-		Axes = (Axis**)calloc(3, sizeof(Axis *));
-		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
-		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
-		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
-			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
-			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
-			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
-			strcpy(label_text, "x-axis");
-			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
-				GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
-			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
-			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
-			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
-			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
-			strcpy(label_text, "y-axis");
-			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
-			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0, 
-				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
-			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		label = 0L;
-		NumAxes = 2;
-		break;
-	case 3:
-		label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
-		Axes = (Axis**)calloc(3, sizeof(Axis *));
-		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
-		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
-		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_TOP | utick |	
-			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
-			Axes[0]->SetSize(SIZE_LB_YDIST, -lb_ydist);
-			Axes[0]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
-			strcpy(label_text, "x-axis");
-			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
-				GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
-			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
-			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
-			AXIS_AUTOSCALE | AXIS_INVERT | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
-			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
-			strcpy(label_text, "y-axis");
-			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
-			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0, 
-				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
-			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		label = 0L;
-		NumAxes = 2;
-		break;
-	case 4:
-		Axes = (Axis**)calloc(3, sizeof(Axis *));
-		if(x_axis.Start >= 0.0f) x_axis.min = -x_axis.Step;
-		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
-		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
-		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
-		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
-		y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
-		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
-			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
-			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
-			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
-			strcpy(label_text, "x-axis");
-			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
-				GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
-			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
-			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
-			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
-			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
-			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
-			strcpy(label_text, "y-axis");
-			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
-			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0, 
-				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
-			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
-			else if(label) DeleteGO(label);
-			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
-			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
-			}
-		label = 0L;
-		NumAxes = 2;
-		break;
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Pages are graphic objects containing graphs and drawn objects
-Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L)
-{
-	FileIO(INIT_VARS);
-	cGraphs--;		cPages++;		Id = GO_PAGE;	bModified = true;
-}
-
-Page::Page(int src):Graph(src)
-{
-	int i;
-
-	//most of the object is read by Graph::FileIO()
-	ColBG = 0x00e8e8e8L;
-	LineDef.width = 0.0;	LineDef.patlength = 1.0;
-	LineDef.color = LineDef.pattern = 0x0L;
-	FillDef.type = FILL_NONE;
-	FillDef.color = 0x00ffffffL;	//use white paper
-	FillDef.scale = 1.0;
-	FillDef.hatch = 0L;
-	cGraphs--;		cPages++;	bModified = false;
-	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->moveable = 1;
-}
-
-void
-Page::DoPlot(anyOutput *o)
-{
-	int i;
-	POINT pts[3];
-
-	if(!o && !Disp) {
-		Disp = NewDispClass(this);
-		Disp->SetMenu(MENU_PAGE);
-		sprintf(TmpTxt, "Page %d", cPages);
-		if(!name) name = strdup(TmpTxt);			Disp->Caption(TmpTxt);
-		Disp->VPorg.fy = iround(Disp->MenuHeight);
-		Disp->VPscale = 0.5;
-		Disp->CheckMenu(ToolMode, true);
-		OwnDisp = true;
-		}
-	//the first output class is the display class
-	if(!Disp && (!(Disp = o))) return;
-	CurrDisp = o ? o : Disp;
-	CurrDisp->Erase(CurrDisp->dFillCol = ColBG);
-	if(OwnDisp && CurrDisp == Disp)LineDef.color = 0x0L;
-	else LineDef.color = FillDef.color;
-	CurrDisp->SetLine(&LineDef);
-	CurrDisp->SetFill(&FillDef);
-	CurrDisp->oRectangle(rDims.left = CurrDisp->co2ix(GRect.Xmin), 
-		rDims.top = CurrDisp->co2iy(GRect.Ymin), rDims.right = CurrDisp->co2ix(GRect.Xmax),
-		rDims.bottom = CurrDisp->co2iy(GRect.Ymax));
-	pts[0].x = rDims.left+7;				pts[0].y = pts[1].y = rDims.bottom;
-	pts[1].x = pts[2].x = rDims.right;		pts[2].y = rDims.top +3;
-	CurrDisp->oPolyline(pts, 3);
-	//do all plots
+				if(!((Plot*)Plots[i])->hidden) {
+					if(x_axis.flags & AXIS_AUTOSCALE) {
+						Bounds.Xmin = ((Plot*)Plots[i])->Bounds.Xmin < Bounds.Xmin ?
+							((Plot*)Plots[i])->Bounds.Xmin : Bounds.Xmin;
+						Bounds.Xmax = ((Plot*)Plots[i])->Bounds.Xmax > Bounds.Xmax ?
+							((Plot*)Plots[i])->Bounds.Xmax : Bounds.Xmax;
+						}
+					if(y_axis.flags & AXIS_AUTOSCALE) {
+						Bounds.Ymin = ((Plot*)Plots[i])->Bounds.Ymin < Bounds.Ymin ?
+							((Plot*)Plots[i])->Bounds.Ymin : Bounds.Ymin;
+						Bounds.Ymax = ((Plot*)Plots[i])->Bounds.Ymax > Bounds.Ymax ?
+							((Plot*)Plots[i])->Bounds.Ymax : Bounds.Ymax;
+						}
+					}
+				}
+			}
+		if(Bounds.Xmax <= Bounds.Xmin) {
+			Bounds.Xmax = oB.Xmax > oB.Xmin ? oB.Xmax : oB.Xmax + 1.0;
+			Bounds.Xmin = oB.Xmin < oB.Xmax ? oB.Xmin : oB.Xmin - 1.0;
+			}
+		if(Bounds.Ymax <= Bounds.Ymin) {
+			Bounds.Ymax = oB.Ymax > oB.Ymin ? oB.Ymax : oB.Ymax + 1.0;
+			Bounds.Ymin = oB.Ymin < oB.Ymax ? oB.Ymin : oB.Ymin - 1.0;
+			}
+		if(x_axis.flags & AXIS_AUTOSCALE){
+			x_axis.min = Bounds.Xmin;	x_axis.max = Bounds.Xmax;
+			NiceAxis(&x_axis, 4);
+			if(x_axis.min <= 0.0 && ((x_axis.flags & 0xf000) == AXIS_LOG ||
+				(x_axis.flags & 0xf000) == AXIS_RECI)) {
+				x_axis.min = base4log(&x_axis, 0);
+				}
+			if(Axes)for(i = 0; i < NumAxes; i++)
+				if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, 0L);
+			}
+		if(y_axis.flags & AXIS_AUTOSCALE){
+			y_axis.min = Bounds.Ymin;	y_axis.max = Bounds.Ymax;
+			NiceAxis(&y_axis, 4);
+			if(y_axis.min <= 0.0 && ((y_axis.flags & 0xf000) == AXIS_LOG ||
+				(y_axis.flags & 0xf000) == AXIS_RECI)) {
+				y_axis.min = base4log(&y_axis, 1);
+				}
+			if(Axes)for(i = 0; i < NumAxes; i++)
+				if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, 0L);
+			}
+		}
+	dirty = false;
+}
+
+void
+Graph::CreateAxes(int templ)
+{
+	AxisDEF tmp_axis;
+	TextDEF label_def, tlbdef;
+	char label_text[500];
+	Label *label;
+	double ts, lb_ydist, lb_xdist, tlb_dist;
+	DWORD ptick, ntick, utick;
+	char xa_desc[50], ya_desc[50];
+
+	if(Axes && NumAxes) return;
+	label_def.ColTxt = defs.Color(COL_AXIS);				label_def.ColBg = 0x00ffffffL;
+	label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2;		label_def.RotBL = label_def.RotCHAR = 0.0;
+	label_def.iSize = 0;									label_def.Align = TXA_VTOP | TXA_HCENTER;
+	label_def.Mode = TXM_TRANSPARENT;						label_def.Style = TXS_NORMAL;
+	label_def.Font = FONT_HELVETICA;						label_def.text = label_text;
+	tlbdef.ColTxt = defs.Color(COL_AXIS);					tlbdef.ColBg = 0x00ffffffL;
+	tlbdef.RotBL = tlbdef.RotCHAR = 0.0;					tlbdef.iSize = 0;
+	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);				tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+	tlbdef.Style = TXS_NORMAL;								tlbdef.Mode = TXM_TRANSPARENT;
+	tlbdef.Font = FONT_HELVETICA;							tlbdef.text = 0L;
+	ts = DefSize(SIZE_AXIS_TICKS);
+	rlp_strcpy(xa_desc, 50, (char*)"x-axis");				rlp_strcpy(ya_desc, 50, (char*)"y-axis");
+	if(Plots && NumPlots && Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH) {
+		if(((Plot*)Plots[0])->x_info) rlp_strcpy(xa_desc, 50,((Plot*)Plots[0])->x_info); 
+		if(((Plot*)Plots[0])->y_info) rlp_strcpy(ya_desc, 50,((Plot*)Plots[0])->y_info); 
+		}
+	switch (tickstyle & 0x07){
+	case 1:						//ticks inside
+		ntick = AXIS_POSTICKS;		ptick = AXIS_POSTICKS;	utick = AXIS_NEGTICKS;
+		ts *= 0.5;
+		break;
+	case 2:						//centered, symetrical
+		ptick = ntick = utick = AXIS_SYMTICKS;
+		ts *= 0.75;
+		break;
+	default:					//ticks outside
+		ptick = AXIS_NEGTICKS;		ntick = AXIS_NEGTICKS; utick = AXIS_POSTICKS;
+		break;
+		}
+	tlb_dist = NiceValue(ts * 2.0);
+	lb_ydist = NiceValue((ts+DefSize(SIZE_AXIS_TICKS))*2.0);
+	lb_xdist = NiceValue((ts+DefSize(SIZE_AXIS_TICKS))*3.0);
+	switch(templ) {
+	case 0:
+		Axes = (Axis**)calloc(5, sizeof(Axis *));
+		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;;
+		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
+			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+			rlp_strcpy(label_text, 500, xa_desc);
+			label = new Label(Axes[0], data, (DRect.Xmin+DRect.Xmax)/2.0, 
+				GRect.Ymin+DRect.Ymax+DefSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
+			rlp_strcpy(label_text, 500, ya_desc);
+			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0, 
+				(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		label = 0L;
+		memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
+		tmp_axis.owner = NULL;
+		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		if((Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK))){
+			Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist); 
+			Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist); 
+			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+			Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
+		tmp_axis.owner = NULL;
+		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		if((Axes[3] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK))){
+			Axes[3]->SetSize(SIZE_LB_XDIST, lb_xdist); 
+			Axes[3]->SetSize(SIZE_TLB_XDIST, tlb_dist); 
+			tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+			Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		NumAxes = 4;
+		break;
+	case 1:
+		Axes = (Axis**)calloc(7, sizeof(Axis *));
+		if(x_axis.Start >= 0.0f) x_axis.min = x_axis.Start = -x_axis.Step;
+		if(y_axis.Start >= 0.0f) y_axis.min = y_axis.Start = -y_axis.Step;
+		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		x_axis.loc[0].fy = x_axis.loc[1].fy = 0.0f;
+		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
+		if((Axes[0] = new Axis(this, data, &x_axis, ptick | AXIS_Y_DATA |	
+			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+			rlp_strcpy(label_text, 500, xa_desc);
+			label_def.Align = TXA_VTOP | TXA_HRIGHT;
+			label = new Label(Axes[0], data, GRect.Xmin + DRect.Xmax - DefSize(SIZE_AXIS_TICKS)*2.0, 
+				GRect.Ymin+DRect.Ymax+DefSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
+			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+			rlp_strcpy(label_text, 500, ya_desc);
+			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HRIGHT;
+			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0, 
+				GRect.Ymin + DRect.Ymin + DefSize(SIZE_AXIS_TICKS)*2.0, 
+				&label_def, LB_X_PARENT);
+			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
+		tmp_axis.owner = NULL;
+		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		if(Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK)){
+			Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist); 
+			Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
+			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+			Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
+		if(Axes[3] = new Axis(this, data, &tmp_axis, AXIS_BOTTOM | AXIS_NOTICKS | AXIS_AUTOTICK)){
+			Axes[3]->SetSize(SIZE_LB_YDIST, lb_xdist); 
+			Axes[3]->SetSize(SIZE_TLB_YDIST, tlb_dist); 
+			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+			Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
+		tmp_axis.owner = NULL;
+		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+		if(Axes[4] = new Axis(this, data, &tmp_axis, AXIS_LEFT | AXIS_NOTICKS | AXIS_AUTOTICK)){
+			Axes[4]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[4]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[4]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		if(Axes[5] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK)){
+			Axes[5]->SetSize(SIZE_LB_XDIST, lb_xdist); 
+			Axes[5]->SetSize(SIZE_TLB_XDIST, tlb_dist); 
+			tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+			Axes[5]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		NumAxes = 6;
+		break;
+	case 2:
+		Axes = (Axis**)calloc(3, sizeof(Axis *));
+		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
+			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+			rlp_strcpy(label_text, 500, xa_desc);
+			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
+				GRect.Ymin+DRect.Ymax+DefSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
+			rlp_strcpy(label_text, 500, ya_desc);
+			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0, 
+				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		label = 0L;
+		NumAxes = 2;
+		break;
+	case 3:
+		label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+		Axes = (Axis**)calloc(3, sizeof(Axis *));
+		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_TOP | utick |	
+			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+			Axes[0]->SetSize(SIZE_LB_YDIST, -lb_ydist);
+			Axes[0]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
+			rlp_strcpy(label_text, 500, xa_desc);
+			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
+				GRect.Ymin+DRect.Ymax+DefSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+			AXIS_AUTOSCALE | AXIS_INVERT | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
+			rlp_strcpy(label_text, 500, ya_desc);
+			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0, 
+				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		label = 0L;
+		NumAxes = 2;
+		break;
+	case 4:
+		Axes = (Axis**)calloc(3, sizeof(Axis *));
+		if(x_axis.Start >= 0.0f) x_axis.min = -x_axis.Step;
+		x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+		x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+		x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+		y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+		y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
+		if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |	
+			AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+			Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+			Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+			rlp_strcpy(label_text, 500, xa_desc);
+			label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f, 
+				GRect.Ymin+DRect.Ymax+DefSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+			if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+			Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
+			AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+			Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist); 
+			Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist); 
+			rlp_strcpy(label_text, 500, ya_desc);
+			label_def.RotBL = 90.0;			label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+			label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0, 
+				GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+			if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+			else if(label) DeleteGO(label);
+			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+			Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			}
+		label = 0L;
+		NumAxes = 2;
+		break;
+		}
+}
+
+bool
+Graph::DoScale(scaleINFO* sc, anyOutput *o)
+{
+	int i;
+	double x0, y0, z0;
+
+	if(sc->sy.fy > 0.0) {
+		scale = scale > 0.0 ? scale * sc->sy.fy : sc->sy.fy;
+		}
+	else return false;
+	GRect.Xmax = sc->sx.fx + GRect.Xmax* sc->sx.fy;
+	GRect.Xmin = sc->sx.fx + GRect.Xmin * sc->sx.fy;
+	GRect.Ymax = sc->sy.fx + GRect.Ymax * sc->sy.fy;
+	GRect.Ymin = sc->sy.fx + GRect.Ymin * sc->sy.fy;
+	DRect.Xmax *= sc->sx.fy;	DRect.Xmin *= sc->sx.fy;
+	DRect.Ymax *= sc->sy.fy;	DRect.Ymin *= sc->sy.fy;
+	x0 = sc->sx.fx;		y0 = sc->sy.fx;		z0= sc->sz.fx;
+	sc->sx.fx = sc->sy.fx = sc->sz.fx = 0.0;	sc->sx.fy = sc->sz.fy = sc->sy.fy;
+	if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(CMD_SCALE, sc, o);
+	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->Command(CMD_SCALE, sc, o);
+	sc->sx.fx = x0;		sc->sy.fx = y0;		sc->sz.fx = z0;
+	return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Pages are graphic objects containing graphs and drawn objects
+Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L)
+{
+	FileIO(INIT_VARS);
+	cGraphs--;		cPages++;		Id = GO_PAGE;	bModified = true;
+}
+
+Page::Page(int src):Graph(src)
+{
+	int i;
+
+	//most of the object is read by Graph::FileIO()
+	ColBG = 0x00e8e8e8L;
+	LineDef.width = 0.0;	LineDef.patlength = 1.0;
+	LineDef.color = LineDef.pattern = 0x0L;
+	FillDef.type = FILL_NONE;
+	FillDef.color = 0x00ffffffL;	//use white paper
+	FillDef.scale = 1.0;
+	FillDef.hatch = 0L;
+	cGraphs--;		cPages++;	bModified = false;
+	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->moveable = 1;
+}
+
+void
+Page::DoPlot(anyOutput *o)
+{
+	int i;
+	POINT pts[3];
+
+	if(!o && !Disp) {
+		Disp = NewDispClass(this);
+		Disp->SetMenu(MENU_PAGE);
+#ifdef USE_WIN_SECURE
+		i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Page %d", cPages);
+#else
+		i = sprintf(TmpTxt, "Page %d", cPages);
+#endif
+		if(!name && (name = (char*)malloc(i += 2)))rlp_strcpy(name, i, TmpTxt);
+		Disp->Caption(TmpTxt);
+		Disp->VPorg.fy = iround(Disp->MenuHeight);
+		Disp->VPscale = 0.5;
+		Disp->CheckMenu(ToolMode, true);
+		OwnDisp = true;
+		}
+	//the first output class is the display class
+	if(!Disp && (!(Disp = o))) return;
+	CurrDisp = o ? o : Disp;
+	CurrDisp->Erase(CurrDisp->dFillCol = ColBG);
+	if(OwnDisp && CurrDisp == Disp)LineDef.color = 0x0L;
+	else LineDef.color = FillDef.color;
+	CurrDisp->SetLine(&LineDef);
+	CurrDisp->SetFill(&FillDef);
+	CurrDisp->oRectangle(rDims.left = CurrDisp->co2ix(GRect.Xmin), 
+		rDims.top = CurrDisp->co2iy(GRect.Ymin), rDims.right = CurrDisp->co2ix(GRect.Xmax),
+		rDims.bottom = CurrDisp->co2iy(GRect.Ymax));
+	pts[0].x = rDims.left+7;				pts[0].y = pts[1].y = rDims.bottom;
+	pts[1].x = pts[2].x = rDims.right;		pts[2].y = rDims.top +3;
+	CurrDisp->oPolyline(pts, 3);
+	//do all plots
 	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->DoPlot(CurrDisp);
 	if(PasteObj) {
 		ToolMode = TM_PASTE;	CurrDisp->MouseCursor(MC_PASTE, false);
-		}
-}
-
-bool
-Page::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	GraphObj **tmpPlots;
-	Graph *g;
-
-	switch(cmd) {
-	case CMD_MOUSE_EVENT:
-		return Graph::Command(cmd, tmpl, o);
-	case CMD_REDRAW:
-		Disp->StartPage();		DoPlot(Disp);		Disp->EndPage();
-		return true;
-	case CMD_CONFIG:
-		return Configure();
-	case CMD_DROP_GRAPH:
-		if(Disp) {
-			if(!(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2)*sizeof(GraphObj*), 0))) 
-				return false;
-			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-			free(Plots);			Plots = tmpPlots;	Plots[NumPlots] = Plots[NumPlots+1] = 0L;
-			Undo.SetGO(this, &Plots[NumPlots], (GraphObj*)tmpl, 0L);
-			}
-		else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
-			Plots[NumPlots] = (GraphObj*)tmpl;	Plots[NumPlots+1] = 0L;
-			}
-		else return false;
-		if(Plots[NumPlots]){
-			Plots[NumPlots]->parent = this;
-			Plots[NumPlots]->Command(CMD_SET_DATAOBJ, data, 0L);
-			if(Plots[NumPlots]->Id == GO_GRAPH) CurrGraph = (Graph*)Plots[NumPlots];
-			Plots[NumPlots]->moveable = 1;		//all page items should be freely
-			}									//   moveable by user
-		NumPlots++;
-		if(CurrDisp) {
-			CurrDisp->StartPage();		DoPlot(CurrDisp);		CurrDisp->EndPage();
-			}
-		return true;
-	case CMD_NEWGRAPH:
-		if((g = new Graph(this, data, Disp)) && g->PropertyDlg() && 
-			Command(CMD_DROP_GRAPH, g, o))return true;
-		else if(g) DeleteGO(g);
-		return false;
-	case CMD_SET_DATAOBJ:
-		Graph::Command(cmd, tmpl, o);
-		Id = GO_PAGE;
-		return true;
-	default:
-		return Graph::Command(cmd, tmpl, o);
-	}
-}
+		}
+}
+
+bool
+Page::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	Graph *g;
+
+	switch(cmd) {
+	case CMD_MOUSE_EVENT:
+		return Graph::Command(cmd, tmpl, o);
+	case CMD_REDRAW:
+		Disp->StartPage();		DoPlot(Disp);		Disp->EndPage();
+		return true;
+	case CMD_CONFIG:
+		return Configure();
+	case CMD_NEWGRAPH:
+		if((g = new Graph(this, data, Disp)) && g->PropertyDlg() && 
+			Command(CMD_DROP_GRAPH, g, o))return true;
+		else if(g) DeleteGO(g);
+		return false;
+	case CMD_SET_DATAOBJ:
+		Graph::Command(cmd, tmpl, o);
+		Id = GO_PAGE;
+		return true;
+	case CMD_SCALE:
+		return true;
+	default:
+		return Graph::Command(cmd, tmpl, o);
+	}
+}
+
+double 
+Page::DefSize(int select)
+{
+	return defs.GetSize(select);
+}
 
diff --git a/rlplot.h b/rlplot.h
index e38a201..25ac873 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -1,113 +1,122 @@
-//RLPlot.h, Copyright (c) 2000-2006 R.Lackner
-//
-//    This file is part of RLPlot.
-//
-//    RLPlot 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.
-//
-//    RLPlot 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 RLPlot; if not, write to the Free Software
-//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-//
-#define NUM_UNITS  3
-#define TMP_TXT_SIZE 4096
-
-#include <stdio.h>
-#include "Version.h"
-
-#define Swap(a,b) {a^=b;b^=a;a^=b;}
-inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
-inline int WriteFloatToBuff(char *buff, double val) {return sprintf(buff, " %g", val);}
+//RLPlot.h, Copyright (c) 2000-2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot 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.
+//
+//    RLPlot 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 RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+#define NUM_UNITS  3
+#define TMP_TXT_SIZE 4096
+
+#include <stdio.h>
+#include "Version.h"
+
+#define Swap(a,b) {a^=b;b^=a;a^=b;}
+inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
 
 #define _PI		3.1415926535897932384626433832795028841971693993751
 #define _SQRT2	1.4142135623730950488016887242096980785696718753769
-
-#ifdef _WINDOWS
+
+#ifdef _WINDOWS					//platform is windows
+#pragma warning( disable : 4996 )
 #include <windows.h>
-#define w_char unsigned short
+#if _MSC_VER >= 1400
+#define USE_WIN_SECURE
+#endif
+#define w_char unsigned short
 #define _SBINC	1				//scrollbox extra space/line
 #define _TXH	4.0				//graph text default size in mm
-
-#else
-#define DWORD unsigned long
-#define w_char unsigned short
+
+#else							//platform is *nix
+#include <sys/types.h>
+#define DWORD u_int32_t
+#define w_char unsigned short
 #define _SBINC	8				//scrollbox extra space/line
 #define _TXH	3.0				//graph text default size in mm
 #define RLP_PORT	4321		//clipboard server
-
-typedef struct tagPOINT { // pt 
-    long x; 
-    long y; 
-} POINT; 
-
-typedef struct _RECT {    // rc 
-    long left; 
-    long top; 
-    long right; 
-    long bottom; 
-} RECT; 
-
-#endif	//_WINDOWS
-
-enum {SIZE_MINE, SIZE_SYMBOL, SIZE_SYM_LINE, SIZE_DATA_LINE, SIZE_TEXT,
-	SIZE_GRECT_TOP, SIZE_GRECT_BOTTOM, SIZE_GRECT_LEFT, SIZE_GRECT_RIGHT,
-	SIZE_DRECT_LEFT, SIZE_DRECT_RIGHT, SIZE_DRECT_TOP, SIZE_DRECT_BOTTOM,
-	SIZE_DATA_LINE_PAT, SIZE_XPOS, SIZE_XPOS_LAST = SIZE_XPOS+200, 
-	SIZE_YPOS, SIZE_YPOS_LAST = SIZE_YPOS+200, SIZE_ZPOS, 
-	SIZE_ZPOS_LAST = SIZE_ZPOS+200, SIZE_BOUNDS_XMIN,
-	SIZE_BOUNDS_XMAX, SIZE_BOUNDS_YMIN, SIZE_BOUNDS_YMAX, SIZE_BOUNDS_ZMIN,
-	SIZE_BOUNDS_ZMAX, SIZE_BOUNDS_LEFT, SIZE_BAR_BASE,
-	SIZE_BOUNDS_RIGHT, SIZE_BOUNDS_TOP, SIZE_BOUNDS_BOTTOM, SIZE_XAXISY,
-	SIZE_YAXISX, SIZE_AXIS_LINE, SIZE_PATLENGTH, SIZE_BAR_DEPTH,
-	SIZE_AXIS_TICKS, SIZE_TICK_LABELS, SIZE_ERRBAR, SIZE_ERRBAR_LINE, 
-	SIZE_BAR_LINE, SIZE_BAR, SIZE_XBASE, SIZE_YBASE, SIZE_ZBASE, SIZE_BUBBLE_LINE,
-	SIZE_BUBBLE_HATCH_LINE, SIZE_BARMINX, SIZE_BARMINY, SIZE_ARROW_LINE,
-	SIZE_ARROW_CAPWIDTH, SIZE_ARROW_CAPLENGTH, SIZE_HAIRLINE, SIZE_WHISKER,
-	SIZE_WHISKER_LINE, SIZE_BOX_LINE, SIZE_BOXMINX, SIZE_BOXMINY, SIZE_BOX,
-	SIZE_RADIUS1, SIZE_RADIUS2, SIZE_SEGLINE, SIZE_LB_XPOS, SIZE_LB_YPOS,
-	SIZE_LB_XDIST, SIZE_LB_YDIST, SIZE_TLB_XDIST, SIZE_TLB_YDIST, SIZE_ANGLE1,
-	SIZE_ANGLE2, SIZE_XCENTER, SIZE_YCENTER, SIZE_ZCENTER, SIZE_CELLWIDTH, SIZE_CELLTEXT,
-	SIZE_A, SIZE_B, SIZE_MX, SIZE_MY, SIZE_MIN_Z, SIZE_MAX_Z, SIZE_MIN_X, SIZE_MAX_X,
-	SIZE_MIN_Y, SIZE_MAX_Y, SIZE_TICK_ANGLE, SIZE_RRECT_RAD, SIZE_XCENT, SIZE_YCENT,
-	SIZE_ZCENT, SIZE_DRADIUS, SIZE_CURSORPOS, SIZE_CURSOR_XMIN, SIZE_CURSOR_YMIN,
-	SIZE_CURSOR_XMAX, SIZE_CURSOR_YMAX, SIZE_XSTEP, SIZE_LSPC};
-enum {COL_SYM_LINE, COL_SYM_FILL, COL_DATA_LINE, COL_TEXT, COL_BG,
-	COL_AXIS, COL_BAR_LINE, COL_BAR_FILL, COL_ERROR_LINE, COL_BUBBLE_LINE, 
-	COL_BUBBLE_FILLLINE, COL_BUBBLE_FILL, COL_ARROW, COL_WHISKER, COL_BOX_LINE,
-	COL_DRECT, COL_GRECT, COL_GRECTLINE, COL_POLYLINE, COL_POLYGON};
-enum {MRK_NONE, MRK_INVERT, MRK_GODRAW, MRK_SSB_DRAW};
-enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
-	CMD_BACKSP, CMD_CURRLEFT, CMD_CURRIGHT, CMD_CURRUP, CMD_CURRDOWN,
-	CMD_SHIFTLEFT, CMD_SHIFTRIGHT, CMD_SHIFTUP, CMD_SHIFTDOWN,
-	CMD_NEWGRAPH, CMD_DELGRAPH, CMD_DELOBJ, CMD_DROP_PLOT, CMD_DROP_GRAPH, CMD_OPEN,
-	CMD_SAVEDATAAS, CMD_ADDROWCOL, CMD_MOUSE_EVENT, CMD_REDRAW, CMD_DOPLOT,
-	CMD_LBUP, CMD_ENDDIALOG, CMD_RADIOBUTT, CMD_ADDCHILD, CMD_BAR_TYPE,
-	CMD_BAR_FILL, CMD_SET_AXDEF, CMD_SET_DATAOBJ, CMD_SETTEXT, CMD_GETTEXT,
-	CMD_SETTEXTDEF, CMD_GETTEXTDEF, CMD_ADDPLOT, CMD_SYM_TYPE, CMD_SYMTEXT, 
-	CMD_SYMTEXTDEF, CMD_RANGETEXT, CMD_SYM_RANGETEXT, CMD_FOCTXT, CMD_CONTINUE,
-	CMD_ERR_TYPE, CMD_ARROW_ORG, CMD_ARROW_TYPE, CMD_FLUSH, CMD_BOX_FILL,
-	CMD_TABDLG, CMD_NOTABDLG, CMD_TAB, CMD_SHTAB, CMD_BOX_TYPE, CMD_BUBBLE_TYPE,
-	CMD_BUBBLE_ATTRIB, CMD_BUBBLE_FILL, CMD_BUBBLE_LINE, CMD_DL_LINE, 
-	CMD_DL_TYPE, CMD_SEG_FILL, CMD_SEG_LINE, CMD_SELECT, CMD_MOVE, CMD_CUT,
-	CMD_SETSCROLL, CMD_SETHPOS, CMD_SETVPOS, CMD_PG_FILL, CMD_BOUNDS,
-	CMD_SHIFT_OUT, CMD_CAN_CLOSE, CMD_RESET_LINE, CMD_SET_TICKSTYLE,
-	CMD_GET_GRIDLINE, CMD_SET_GRIDLINE, CMD_SET_GRIDTYPE, CMD_TLB_TXTDEF,
-	CMD_DROP_LABEL, CMD_DROP_OBJECT, CMD_PAGEUP, CMD_PAGEDOWN, CMD_AUTOSCALE,
-	CMD_MRK_DIRTY, CMD_SETNAME, CMD_TOOLMODE, CMD_DROPFILE, CMD_AXIS, CMD_INIT,
-	CMD_GET_CELLDIMS, CMD_SET_CELLDIMS, CMD_TEXTSIZE, CMD_PASTE_TSV, CMD_PASTE_XML,
-	CMD_PASTE_SSV, CMD_PASTE_CSV, CMD_COPY_TSV, CMD_COPY_XML, CMD_COPY_SYLK, CMD_QUERY_COPY,
-	CMD_MOUSECURSOR, CMD_NEWPAGE, CMD_MINRC, CMD_MAXRC,CMD_SETCHILD, CMD_SYM_FILL,
-	CMD_LINEUP, CMD_LINEDOWN, CMD_CONFIG, CMD_FINDTEXT, CMD_MOVE_TOP, CMD_MOVE_UP,
-	CMD_MOVE_DOWN, CMD_MOVE_BOTTOM, CMD_UPDATE, CMD_CURRPOS, CMD_POS_FIRST, CMD_POS_LAST,
-	CMD_ADDAXIS, CMD_REG_AXISPLOT, CMD_USEAXIS, CMD_SET_GO3D, CMD_UNDO, CMD_DELOBJ_CONT,
-	CMD_RMU, CMD_REPL_GO, CMD_UNDO_MOVE, CMD_SAVEPOS, CMD_WHISKER_STYLE, CMD_TICK_TYPE,
+#define _strdup	strdup
+#define _open	open
+#define _write	write
+#define _close	close
+#define _lseek	lseek
+
+typedef struct tagPOINT { // pt 
+    long x; 
+    long y; 
+} POINT; 
+
+typedef struct _RECT {    // rc 
+    long left; 
+    long top; 
+    long right; 
+    long bottom; 
+} RECT; 
+
+#endif	//_WINDOWS
+
+enum {SIZE_MINE, SIZE_SYMBOL, SIZE_SYM_LINE, SIZE_DATA_LINE, SIZE_TEXT,
+	SIZE_GRECT_TOP, SIZE_GRECT_BOTTOM, SIZE_GRECT_LEFT, SIZE_GRECT_RIGHT,
+	SIZE_DRECT_LEFT, SIZE_DRECT_RIGHT, SIZE_DRECT_TOP, SIZE_DRECT_BOTTOM,
+	SIZE_DATA_LINE_PAT, SIZE_XPOS, SIZE_XPOS_LAST = SIZE_XPOS+200, 
+	SIZE_YPOS, SIZE_YPOS_LAST = SIZE_YPOS+200, SIZE_ZPOS, 
+	SIZE_ZPOS_LAST = SIZE_ZPOS+200, SIZE_BOUNDS_XMIN,
+	SIZE_BOUNDS_XMAX, SIZE_BOUNDS_YMIN, SIZE_BOUNDS_YMAX, SIZE_BOUNDS_ZMIN,
+	SIZE_BOUNDS_ZMAX, SIZE_BOUNDS_LEFT, SIZE_BAR_BASE,
+	SIZE_BOUNDS_RIGHT, SIZE_BOUNDS_TOP, SIZE_BOUNDS_BOTTOM, SIZE_XAXISY,
+	SIZE_YAXISX, SIZE_AXIS_LINE, SIZE_PATLENGTH, SIZE_BAR_DEPTH,
+	SIZE_AXIS_TICKS, SIZE_TICK_LABELS, SIZE_ERRBAR, SIZE_ERRBAR_LINE, 
+	SIZE_BAR_LINE, SIZE_BAR, SIZE_XBASE, SIZE_YBASE, SIZE_ZBASE, SIZE_BUBBLE_LINE,
+	SIZE_BUBBLE_HATCH_LINE, SIZE_BARMINX, SIZE_BARMINY, SIZE_ARROW_LINE,
+	SIZE_ARROW_CAPWIDTH, SIZE_ARROW_CAPLENGTH, SIZE_HAIRLINE, SIZE_WHISKER,
+	SIZE_WHISKER_LINE, SIZE_BOX_LINE, SIZE_BOXMINX, SIZE_BOXMINY, SIZE_BOX,
+	SIZE_RADIUS1, SIZE_RADIUS2, SIZE_SEGLINE, SIZE_LB_XPOS, SIZE_LB_YPOS,
+	SIZE_LB_XDIST, SIZE_LB_YDIST, SIZE_TLB_XDIST, SIZE_TLB_YDIST, SIZE_ANGLE1,
+	SIZE_ANGLE2, SIZE_XCENTER, SIZE_YCENTER, SIZE_ZCENTER, SIZE_CELLWIDTH, SIZE_CELLTEXT,
+	SIZE_A, SIZE_B, SIZE_MX, SIZE_MY, SIZE_MIN_Z, SIZE_MAX_Z, SIZE_MIN_X, SIZE_MAX_X,
+	SIZE_MIN_Y, SIZE_MAX_Y, SIZE_TICK_ANGLE, SIZE_RRECT_RAD, SIZE_XCENT, SIZE_YCENT,
+	SIZE_ZCENT, SIZE_DRADIUS, SIZE_CURSORPOS, SIZE_CURSOR_XMIN, SIZE_CURSOR_YMIN,
+	SIZE_CURSOR_XMAX, SIZE_CURSOR_YMAX, SIZE_XSTEP, SIZE_LSPC};
+enum {COL_SYM_LINE, COL_SYM_FILL, COL_DATA_LINE, COL_TEXT, COL_BG,
+	COL_AXIS, COL_BAR_LINE, COL_BAR_FILL, COL_ERROR_LINE, COL_BUBBLE_LINE, 
+	COL_BUBBLE_FILLLINE, COL_BUBBLE_FILL, COL_ARROW, COL_WHISKER, COL_BOX_LINE,
+	COL_DRECT, COL_GRECT, COL_GRECTLINE, COL_POLYLINE, COL_POLYGON};
+enum {MRK_NONE, MRK_INVERT, MRK_GODRAW, MRK_SSB_DRAW};
+enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
+	CMD_BACKSP, CMD_CURRLEFT, CMD_CURRIGHT, CMD_CURRUP, CMD_CURRDOWN,
+	CMD_SHIFTLEFT, CMD_SHIFTRIGHT, CMD_SHIFTUP, CMD_SHIFTDOWN,
+	CMD_NEWGRAPH, CMD_DELGRAPH, CMD_DELOBJ, CMD_DROP_PLOT, CMD_DROP_GRAPH, CMD_OPEN,
+	CMD_SAVEDATAAS, CMD_ADDROWCOL, CMD_MOUSE_EVENT, CMD_REDRAW, CMD_DOPLOT,
+	CMD_LBUP, CMD_ENDDIALOG, CMD_RADIOBUTT, CMD_ADDCHILD, CMD_BAR_TYPE,
+	CMD_BAR_FILL, CMD_SET_AXDEF, CMD_SET_DATAOBJ, CMD_SETTEXT, CMD_GETTEXT,
+	CMD_SETTEXTDEF, CMD_GETTEXTDEF, CMD_ADDPLOT, CMD_SYM_TYPE, CMD_SYMTEXT, 
+	CMD_SYMTEXTDEF, CMD_RANGETEXT, CMD_SYM_RANGETEXT, CMD_FOCTXT, CMD_CONTINUE,
+	CMD_ERR_TYPE, CMD_ARROW_ORG, CMD_ARROW_TYPE, CMD_FLUSH, CMD_BOX_FILL,
+	CMD_TABDLG, CMD_NOTABDLG, CMD_TAB, CMD_SHTAB, CMD_BOX_TYPE, CMD_BUBBLE_TYPE,
+	CMD_BUBBLE_ATTRIB, CMD_BUBBLE_FILL, CMD_BUBBLE_LINE, CMD_DL_LINE, 
+	CMD_DL_TYPE, CMD_SEG_FILL, CMD_SEG_LINE, CMD_SELECT, CMD_MOVE, CMD_CUT,
+	CMD_SETSCROLL, CMD_SETHPOS, CMD_SETVPOS, CMD_PG_FILL, CMD_BOUNDS,
+	CMD_SHIFT_OUT, CMD_CAN_CLOSE, CMD_RESET_LINE, CMD_SET_TICKSTYLE,
+	CMD_GET_GRIDLINE, CMD_SET_GRIDLINE, CMD_SET_GRIDTYPE, CMD_TLB_TXTDEF,
+	CMD_DROP_LABEL, CMD_DROP_OBJECT, CMD_PAGEUP, CMD_PAGEDOWN, CMD_AUTOSCALE,
+	CMD_MRK_DIRTY, CMD_SETNAME, CMD_TOOLMODE, CMD_DROPFILE, CMD_AXIS, CMD_INIT,
+	CMD_GET_CELLDIMS, CMD_SET_CELLDIMS, CMD_TEXTSIZE, CMD_PASTE_TSV, CMD_PASTE_XML,
+	CMD_PASTE_SSV, CMD_PASTE_CSV, CMD_COPY_TSV, CMD_COPY_XML, CMD_COPY_SYLK, CMD_QUERY_COPY,
+	CMD_MOUSECURSOR, CMD_NEWPAGE, CMD_MINRC, CMD_MAXRC,CMD_SETCHILD, CMD_SYM_FILL,
+	CMD_LINEUP, CMD_LINEDOWN, CMD_CONFIG, CMD_FINDTEXT, CMD_MOVE_TOP, CMD_MOVE_UP,
+	CMD_MOVE_DOWN, CMD_MOVE_BOTTOM, CMD_UPDATE, CMD_CURRPOS, CMD_POS_FIRST, CMD_POS_LAST,
+	CMD_ADDAXIS, CMD_REG_AXISPLOT, CMD_USEAXIS, CMD_SET_GO3D, CMD_UNDO, CMD_DELOBJ_CONT,
+	CMD_RMU, CMD_REPL_GO, CMD_UNDO_MOVE, CMD_SAVEPOS, CMD_WHISKER_STYLE, CMD_TICK_TYPE,
 	CMD_ZOOM, CMD_CLIP, CMD_STARTLINE, CMD_ADDTOLINE, CMD_REQ_POINT, CMD_DRAW_LATER,
 	CMD_SEG_MOVEABLE, CMD_ARROW_ORG3D, CMD_MUTATE, CMD_PRINT, CMD_UPDHISTORY, CMD_ALLTEXT,
 	CMD_SET_LINE, CMD_SAVE_SYMBOLS, CMD_SAVE_TICKS, CMD_SAVE_BARS, CMD_SAVE_BARS_CONT,
@@ -116,202 +125,207 @@ enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
 	CMD_HIDE_MARK, CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
 	CMD_HASSTACK, CMD_WRITE_GRAPHS, CMD_SETFONT, CMD_SETSTYLE, CMD_COPY, CMD_PASTE,
 	CMD_INSROW, CMD_INSCOL, CMD_DELROW, CMD_DELCOL, CMD_ADDTXT, CMD_ETRACC, CMD_SHPGUP, 
-	CMD_SHPGDOWN, CMD_ERRDESC, CMD_SAVEDATA, CMD_GETMARK, CMD_PASTE_OBJ};
-enum {SYM_CIRCLE, SYM_CIRCLEF, SYM_RECT, SYM_RECTF, SYM_TRIAU, SYM_TRIAUF,
-	SYM_TRIAD, SYM_TRIADF, SYM_DIAMOND, SYM_DIAMONDF, SYM_PLUS, SYM_CROSS,
-	SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT, SYM_POS_PARENT = 0x1000};
-//types of graphic objects: stored in Id and used for proper destruction of objects
-//  and retrieving information.
-enum {GO_UNKNOWN, GO_AXIS, GO_TICK, GO_GRIDLINE, GO_SYMBOL, GO_BUBBLE, GO_BAR, 
-	GO_ERRBAR, GO_ARROW, GO_BOX, GO_LABEL, GO_MLABEL, GO_WHISKER, GO_DROPLINE, 
-	GO_DATALINE, GO_DATAPOLYGON, GO_REGLINE, GO_SDELLIPSE, GO_SEGMENT, 
-	GO_POLYLINE, GO_POLYGON, GO_RECTANGLE, GO_ELLIPSE, GO_ROUNDREC,
-	GO_DRAGHANDLE, GO_DRAGRECT, GO_DRAG3D, GO_FRAMERECT, GO_SPHERE, GO_SVGOPTIONS,
-	GO_PLANE, GO_BRICK, GO_LINESEG, GO_LINE3D, GO_GRIDLINE3D, GO_GRIDRADIAL,
+	CMD_SHPGDOWN, CMD_ERRDESC, CMD_SAVEDATA, CMD_GETMARK, CMD_PASTE_OBJ, CMD_COL_MOUSE,
+	CMD_MARKOBJ, CMD_SCALE};
+enum {SYM_CIRCLE, SYM_CIRCLEF, SYM_RECT, SYM_RECTF, SYM_TRIAU, SYM_TRIAUF,
+	SYM_TRIAD, SYM_TRIADF, SYM_DIAMOND, SYM_DIAMONDF, SYM_PLUS, SYM_CROSS,
+	SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT, SYM_POS_PARENT = 0x1000};
+//types of graphic objects: stored in Id and used for proper destruction of objects
+//  and retrieving information.
+enum {GO_UNKNOWN, GO_AXIS, GO_TICK, GO_GRIDLINE, GO_SYMBOL, GO_BUBBLE, GO_BAR, 
+	GO_ERRBAR, GO_ARROW, GO_BOX, GO_LABEL, GO_MLABEL, GO_WHISKER, GO_DROPLINE, 
+	GO_DATALINE, GO_DATAPOLYGON, GO_REGLINE, GO_SDELLIPSE, GO_SEGMENT, 
+	GO_POLYLINE, GO_POLYGON, GO_RECTANGLE, GO_ELLIPSE, GO_ROUNDREC,
+	GO_DRAGHANDLE, GO_DRAGRECT, GO_DRAG3D, GO_FRAMERECT, GO_SPHERE, GO_SVGOPTIONS,
+	GO_PLANE, GO_BRICK, GO_LINESEG, GO_LINE3D, GO_GRIDLINE3D, GO_GRIDRADIAL,
 	GO_SPHSCANL, GO_DROPL3D, GO_ARROW3D, GO_PLANE3D, GO_LEGITEM, GO_LEGEND,
-	GO_OBJTREE, GO_BEZIER,
-	GO_PLOT = 0x100, GO_PLOTSCATT, GO_REGRESSION, GO_BARCHART, GO_BUBBLEPLOT, 
-	GO_BOXPLOT, GO_DENSDISP, GO_STACKBAR, GO_STACKPG, GO_WATERFALL, GO_POLARPLOT,
-	GO_PIECHART, GO_RINGCHART, GO_GROUP, GO_STARCHART, GO_SCATT3D, GO_PLOT3D,
+	GO_OBJTREE, GO_BEZIER, GO_TEXTFRAME,
+	GO_PLOT = 0x100, GO_PLOTSCATT, GO_REGRESSION, GO_BARCHART, GO_BUBBLEPLOT, 
+	GO_BOXPLOT, GO_DENSDISP, GO_STACKBAR, GO_STACKPG, GO_WATERFALL, GO_POLARPLOT,
+	GO_PIECHART, GO_RINGCHART, GO_GROUP, GO_STARCHART, GO_SCATT3D, GO_PLOT3D,
 	GO_RIBBON, GO_LIMITS, GO_FUNCTION, GO_FITFUNC, GO_FREQDIST, GO_GRID3D, GO_FUNC3D,
-	GO_XYSTAT, GO_FITFUNC3D,
-	GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
-enum {FILL_NONE, FILL_HLINES, FILL_VLINES, FILL_HVCROSS, FILL_DLINEU, FILL_DLINED,
-	FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4, 
-	FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU, 
-	FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES, 
+	GO_XYSTAT, GO_FITFUNC3D,
+	GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
+enum {FILL_NONE, FILL_HLINES, FILL_VLINES, FILL_HVCROSS, FILL_DLINEU, FILL_DLINED,
+	FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4, 
+	FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU, 
+	FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES, 
 	FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS, 
-	FILL_HASH, FILL_WATER, NUM_FILLS, FILL_LIGHT3D = 0x100};
-enum {ERRBAR_VSYM, ERRBAR_VUP, ERRBAR_VDOWN, ERRBAR_HSYM, ERRBAR_HLEFT,
-	ERRBAR_HRIGHT};
-enum {BAR_NONE, BAR_VERTB, BAR_VERTT, BAR_VERTU, BAR_HORL, BAR_HORR, BAR_HORU, 
-	BAR_RELWIDTH = 0x100, BAR_CENTERED = 0x200, BAR_WIDTHDATA = 0x400};
-enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
+	FILL_HASH, FILL_WATER, NUM_FILLS, FILL_LIGHT3D = 0x100};
+enum {ERRBAR_VSYM, ERRBAR_VUP, ERRBAR_VDOWN, ERRBAR_HSYM, ERRBAR_HLEFT,
+	ERRBAR_HRIGHT};
+enum {BAR_NONE, BAR_VERTB, BAR_VERTT, BAR_VERTU, BAR_HORL, BAR_HORR, BAR_HORU, 
+	BAR_RELWIDTH = 0x100, BAR_CENTERED = 0x200, BAR_WIDTHDATA = 0x400};
+enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
 	TM_ROUNDREC, TM_ARROW, TM_TEXT, TM_MARK, TM_ZOOMIN, TM_MOVE = 0x100, 
-	TM_PASTE=0x200};
-enum {MC_LAST, MC_ARROW, MC_CROSS, MC_TEXT, MC_WAIT, MC_MOVE, MC_NORTH,
+	TM_PASTE=0x200};
+enum {MC_LAST, MC_ARROW, MC_CROSS, MC_TEXT, MC_WAIT, MC_MOVE, MC_NORTH,
 	MC_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM, MC_PASTE, MC_DRAWPEN, MC_DRAWREC, 
-	MC_DRAWRREC, MC_DRAWELLY};
-enum {FILE_ERROR, FILE_READ, FILE_WRITE, INIT_VARS, SAVE_VARS};
-enum {ARROW_NOCAP, ARROW_LINE, ARROW_TRIANGLE, ARROW_UNITS = 0x100};
-enum {MENU_NONE, MENU_SPREAD, MENU_GRAPH, MENU_PAGE};
-enum {GT_UNKNOWN, GT_STANDARD, GT_CIRCCHART, GT_POLARPLOT, GT_3D};
-enum {ICO_NONE, ICO_INFO, ICO_ERROR, ICO_RLPLOT, ICO_QT};
-enum {FF_UNKNOWN, FF_CSV, FF_TSV, FF_XML, FF_SYLK, FF_RLP, FF_SVG, FF_EPS,
-	FF_WMF, FF_RLW, FF_SSV};
-enum {LB_X_DATA = 0x01, LB_X_PARENT = 0x02, LB_Y_DATA = 0x10, LB_Y_PARENT = 0x20};
-enum {BUBBLE_CIRCLE = 0x000, BUBBLE_SQUARE = 0x001, BUBBLE_UPTRIA = 0x002,
-	BUBBLE_DOWNTRIA = 0x003, BUBBLE_UNITS = 0x000, BUBBLE_XAXIS = 0x010,
-	BUBBLE_YAXIS = 0x020, BUBBLE_DIAMET = 0x000, BUBBLE_CIRCUM = 0x100,
-	BUBBLE_AREA = 0x200};
-enum {DH_UNKNOWN, DH_12, DH_22, DH_19, DH_29, DH_39, DH_49, DH_59, DH_69, DH_79,
-	DH_89, DH_99, DH_18, DH_28, DH_38, DH_48, DH_58, DH_68, DH_78, DH_88, DH_DATA};
+	MC_DRAWRREC, MC_DRAWELLY};
+enum {FILE_ERROR, FILE_READ, FILE_WRITE, INIT_VARS, SAVE_VARS};
+enum {ARROW_NOCAP, ARROW_LINE, ARROW_TRIANGLE, ARROW_UNITS = 0x100};
+enum {MENU_NONE, MENU_SPREAD, MENU_GRAPH, MENU_PAGE};
+enum {GT_UNKNOWN, GT_STANDARD, GT_CIRCCHART, GT_POLARPLOT, GT_3D};
+enum {ICO_NONE, ICO_INFO, ICO_ERROR, ICO_RLPLOT, ICO_QT};
+enum {FF_UNKNOWN, FF_CSV, FF_TSV, FF_XML, FF_SYLK, FF_RLP, FF_SVG, FF_EPS,
+	FF_WMF, FF_RLW, FF_SSV};
+enum {LB_X_DATA = 0x01, LB_X_PARENT = 0x02, LB_Y_DATA = 0x10, LB_Y_PARENT = 0x20};
+enum {BUBBLE_CIRCLE = 0x000, BUBBLE_SQUARE = 0x001, BUBBLE_UPTRIA = 0x002,
+	BUBBLE_DOWNTRIA = 0x003, BUBBLE_UNITS = 0x000, BUBBLE_XAXIS = 0x010,
+	BUBBLE_YAXIS = 0x020, BUBBLE_DIAMET = 0x000, BUBBLE_CIRCUM = 0x100,
+	BUBBLE_AREA = 0x200};
+enum {DH_UNKNOWN, DH_12, DH_22, DH_19, DH_29, DH_39, DH_49, DH_59, DH_69, DH_79,
+	DH_89, DH_99, DH_18, DH_28, DH_38, DH_48, DH_58, DH_68, DH_78, DH_88, DH_DATA};
 enum {FE_NONE = 0x1000, FE_PARENT, FE_PLOT, FE_FLUSH, FE_DELOBJ, FE_REPLGO, FE_MUTATE};
-
-//drop line styles
-#define DL_LEFT          0x001
-#define DL_RIGHT         0x002
-#define DL_YAXIS         0x004
-#define DL_TOP           0x010
-#define DL_BOTTOM        0x020
-#define DL_XAXIS         0x040
-#define DL_CIRCULAR      0x100
-
-typedef struct {
-	int num;
-	char* display;
-	float convert;			//multiply to get mm
-	}tag_Units;
-
-typedef struct {
-	int x, y, z;
-	}POINT3D;
-
-typedef struct {
-	double Xmin;
-	double Ymax;
-	double Xmax;
-	double Ymin;
-	}fRECT;
-
-typedef struct {
-	double fx;
-	double fy;
-	double fz;
-	}fPOINT3D;
-
-typedef struct {
-	double fx;
-	double fy;
-	}lfPOINT;
-
-typedef struct {
-	double finc, fp;
-	}RunLinePat;				//used for line patterns
-
-typedef struct {
-	double width, patlength;
-	DWORD color, pattern;
-	}LineDEF;
-
-typedef struct {
-	int type;					//pattern
-	DWORD color;
-	double scale;
-	LineDEF *hatch;
-	DWORD color2;
-	}FillDEF;
-
-typedef struct {
-	lfPOINT org;				//zoom origin
-	double scale;				//zoom factor
-	}ZoomDEF;
-
-// Axis definitions are stored in the following structure
-// not to be confused with the Axis class grapic object
-// bits stored in flags havethe following meaning
-#define AXIS_NOTICKS      0x0			// no ticks at all
-#define AXIS_POSTICKS     0x1			// positive direction of ticks
-#define AXIS_NEGTICKS     0x2			// negative direction 
-#define AXIS_SYMTICKS     0x3			// ticks are symmetrical
-#define AXIS_GRIDLINE     0x4			// ticks control a gridline
-#define AXIS_MINORTICK    0x8			// its a small tick only
-#define AXIS_USER         0x00			// axis placement by user
-#define AXIS_LEFT         0x10			// left of plot
-#define AXIS_RIGHT        0x20			// right  -"-
-#define AXIS_TOP          0x30			// top    -"-
-#define AXIS_BOTTOM       0x40			// bottom -"-
-#define AXIS_AUTOSCALE    0x80			// rescale upon editing
-#define AXIS_INVERT       0x100			// axis top->bottom, right to left
-#define AXIS_AUTOTICK     0x200			// select tick s automatically
-#define AXIS_DEFRECT      0x400			// use axis to define drawing rectangle
-#define AXIS_LINEAR       0x0000		// transforms ...
-#define AXIS_LOG          0x1000
-#define AXIS_RECI         0x2000
-#define AXIS_SQR          0x3000
-#define AXIS_X_DATA       0x10000		// loc.x is data coordinates
-#define AXIS_Y_DATA       0x20000       // loc.y is data coordinates
-#define AXIS_Z_DATA       0x40000       // loc.z is data coordinates
-#define AXIS_ANGULAR      0x100000      // angular (circular) axis
-#define AXIS_RADIAL       0x200000		// radial axis
-#define AXIS_3D           0x400000		// three dimensional axis
-
-typedef struct {
-	void *owner;				//owners are usually graph, output or axis classes
-	DWORD flags;
-	double min, max;
-	fPOINT3D loc[2];			//placement of axis coordinates
-	double Start, Step;			//used for linear axis
-	lfPOINT Center;				//of polar plot
-	double Radius;				//   -"-
-	int nBreaks;				//axis break ...
-	lfPOINT *breaks;
-	}AxisDEF;
-
-//Attributes for text properties
-//Text fonts
-enum {FONT_HELVETICA, FONT_TIMES, FONT_COURIER, FONT_GREEK};
-//Text styles
-#define TXA_VTOP        0
-#define TXA_VCENTER     4
-#define TXA_VBOTTOM     8
-#define TXA_HLEFT       0
-#define TXA_HCENTER     1
-#define TXA_HRIGHT      2
-#define TXM_OPAQUE      0
-#define TXM_TRANSPARENT 1
-#define TXS_NORMAL      0
-#define TXS_ITALIC      1
-#define TXS_BOLD        2
+
+//drop line styles
+#define DL_LEFT          0x001
+#define DL_RIGHT         0x002
+#define DL_YAXIS         0x004
+#define DL_TOP           0x010
+#define DL_BOTTOM        0x020
+#define DL_XAXIS         0x040
+#define DL_CIRCULAR      0x100
+
+typedef struct {
+	int num;
+	char* display;
+	float convert;			//multiply to get mm
+	}tag_Units;
+
+typedef struct {
+	int x, y, z;
+	}POINT3D;
+
+typedef struct {
+	double Xmin;
+	double Ymax;
+	double Xmax;
+	double Ymin;
+	}fRECT;
+
+typedef struct {
+	double fx;
+	double fy;
+	double fz;
+	}fPOINT3D;
+
+typedef struct {
+	double fx;
+	double fy;
+	}lfPOINT;
+
+typedef struct {
+	lfPOINT sx, sy, sz;
+	}scaleINFO;
+
+typedef struct {
+	double finc, fp;
+	}RunLinePat;				//used for line patterns
+
+typedef struct {
+	double width, patlength;
+	DWORD color, pattern;
+	}LineDEF;
+
+typedef struct {
+	int type;					//pattern
+	DWORD color;
+	double scale;
+	LineDEF *hatch;
+	DWORD color2;
+	}FillDEF;
+
+typedef struct {
+	lfPOINT org;				//zoom origin
+	double scale;				//zoom factor
+	}ZoomDEF;
+
+// Axis definitions are stored in the following structure
+// not to be confused with the Axis class grapic object
+// bits stored in flags havethe following meaning
+#define AXIS_NOTICKS      0x0			// no ticks at all
+#define AXIS_POSTICKS     0x1			// positive direction of ticks
+#define AXIS_NEGTICKS     0x2			// negative direction 
+#define AXIS_SYMTICKS     0x3			// ticks are symmetrical
+#define AXIS_GRIDLINE     0x4			// ticks control a gridline
+#define AXIS_MINORTICK    0x8			// its a small tick only
+#define AXIS_USER         0x00			// axis placement by user
+#define AXIS_LEFT         0x10			// left of plot
+#define AXIS_RIGHT        0x20			// right  -"-
+#define AXIS_TOP          0x30			// top    -"-
+#define AXIS_BOTTOM       0x40			// bottom -"-
+#define AXIS_AUTOSCALE    0x80			// rescale upon editing
+#define AXIS_INVERT       0x100			// axis top->bottom, right to left
+#define AXIS_AUTOTICK     0x200			// select tick s automatically
+#define AXIS_DEFRECT      0x400			// use axis to define drawing rectangle
+#define AXIS_LINEAR       0x0000		// transforms ...
+#define AXIS_LOG          0x1000
+#define AXIS_RECI         0x2000
+#define AXIS_SQR          0x3000
+#define AXIS_X_DATA       0x10000		// loc.x is data coordinates
+#define AXIS_Y_DATA       0x20000       // loc.y is data coordinates
+#define AXIS_Z_DATA       0x40000       // loc.z is data coordinates
+#define AXIS_ANGULAR      0x100000      // angular (circular) axis
+#define AXIS_RADIAL       0x200000		// radial axis
+#define AXIS_3D           0x400000		// three dimensional axis
+
+typedef struct {
+	void *owner;				//owners are usually graph, output or axis classes
+	DWORD flags;
+	double min, max;
+	fPOINT3D loc[2];			//placement of axis coordinates
+	double Start, Step;			//used for linear axis
+	lfPOINT Center;				//of polar plot
+	double Radius;				//   -"-
+	int nBreaks;				//axis break ...
+	lfPOINT *breaks;
+	}AxisDEF;
+
+//Attributes for text properties
+//Text fonts
+enum {FONT_HELVETICA, FONT_TIMES, FONT_COURIER, FONT_GREEK};
+//Text styles
+#define TXA_VTOP        0
+#define TXA_VCENTER     4
+#define TXA_VBOTTOM     8
+#define TXA_HLEFT       0
+#define TXA_HCENTER     1
+#define TXA_HRIGHT      2
+#define TXM_OPAQUE      0
+#define TXM_TRANSPARENT 1
+#define TXS_NORMAL      0
+#define TXS_ITALIC      1
+#define TXS_BOLD        2
 #define TXS_UNDERLINE   4
 #define TXS_SUPER       8
-#define TXS_SUB			16
-typedef struct {
-	DWORD ColTxt, ColBg;				//colors ..
-	double fSize;						//Text size in units
-	double RotBL, RotCHAR;				//Rotation in degrees
-	int iSize;							//Text size is given in iSize as pix
-	int Align, Mode, Style;				//Text Alignement 0   1   2
-										//                4   5   6
-										//                8   9  10
-										//Mode 0 = opaque, 1 = transparent
-	int Font;
-	char *text;
-	}TextDEF;
-
-// Store mouse events in the following structure
-// Action defines the type of event:
-enum {MOUSE_LBDOWN, MOUSE_LBUP, MOUSE_LBDOUBLECLICK, MOUSE_MBDOWN, MOUSE_MBUP, 
-	MOUSE_MBDOUBLECLICK, MOUSE_RBDOWN, MOUSE_RBUP, MOUSE_RBDOUBLECLICK,
-	MOUSE_MOVE};
-typedef struct {
-	unsigned short StateFlags;	//  1 Mouse left button down
-								//  2       middle button down
-								//  4       right button down
-								//  8       shift pressed
-								// 16       control pressed
-	unsigned short Action;
-	int x, y;
+#define TXS_SUB			16
+typedef struct {
+	DWORD ColTxt, ColBg;				//colors ..
+	double fSize;						//Text size in units
+	double RotBL, RotCHAR;				//Rotation in degrees
+	int iSize;							//Text size is given in iSize as pix
+	int Align, Mode, Style;				//Text Alignement 0   1   2
+										//                4   5   6
+										//                8   9  10
+										//Mode 0 = opaque, 1 = transparent
+	int Font;
+	char *text;
+	}TextDEF;
+
+// Store mouse events in the following structure
+// Action defines the type of event:
+enum {MOUSE_LBDOWN, MOUSE_LBUP, MOUSE_LBDOUBLECLICK, MOUSE_MBDOWN, MOUSE_MBUP, 
+	MOUSE_MBDOUBLECLICK, MOUSE_RBDOWN, MOUSE_RBUP, MOUSE_RBDOUBLECLICK,
+	MOUSE_MOVE};
+typedef struct {
+	unsigned short StateFlags;	//  1 Mouse left button down
+								//  2       middle button down
+								//  4       right button down
+								//  8       shift pressed
+								// 16       control pressed
+	unsigned short Action;
+	int x, y;
 	} MouseEvent;
 
 //use this structure if type of data is not known
@@ -319,167 +333,202 @@ typedef struct {
 	int type;
 	double value;
 	char *text;
-	} anyResult;
-
-//the AccRange class allows to access data objects with a 'a1:b1' style
-class AccRange{
-public:
-	AccRange(char *asc);
-	~AccRange();
-	int CountItems();
-	bool GetFirst(int *x, int *y);
+	} anyResult;
+
+//the AccRange class allows to access data objects with a 'a1:b1' style
+class AccRange{
+public:
+	AccRange(char *asc);
+	~AccRange();
+	int CountItems();
+	bool GetFirst(int *x, int *y);
 	bool GetNext(int *x, int *y);
 	bool NextRow(int *y);
-	bool NextCol(int *x);
-	bool IsInRange(int x, int y);
-	bool BoundRec(RECT *rec);
-
-private:
-	char *txt;
-	int x1, y1, x2, y2, cx, cy, curridx;
-
-	bool Reset();
-	bool Parse(int start);
-};
-
-class anyOutput{
-public:
-	int units;							//use units mm, inch ...
-	int MrkMode;						//existing mark on screen
-	void *MrkRect;						//pointer to e.g. the marked rectangle
-	fRECT Box1;							//User drawing rectangle
-	lfPOINT Box1z;						// add 3D to Box1
-	RECT DeskRect;						//this is maximum size Rectangle
-	double ddx, ddy, ddz;				//convert to device coordinates
-	double hres, vres;					//resolution in dpi
-	double LineWidth;					//line width in units
-	int iLine;							//current width of line in pixels
-	DWORD dLineCol;						//current color of line;
-	DWORD dBgCol;						//color of background
-	DWORD dFillCol, dFillCol2;
-	DWORD dPattern;						//current line bit-pattern
-	TextDEF TxtSet;						//store current text settings here
-	RunLinePat RLP;						//continuous setings of pattern line
-	AxisDEF xAxis, yAxis, zAxis;		//axis and transform definitions
-	lfPOINT VPorg;						//zoom origin
-	double VPscale;						//zoom factor
-	int MenuHeight;						//ofset due to pull down menus
-	int cCursor;						//mouse coursor identifier
-	double rotM[3][3];					//rotation matrix for 3D
-	fPOINT3D rotC;						//rotation center
-	bool hasHistMenu;					//File History List
-	int HistMenuSize;					//     -"-
-	lfPOINT light_source;				//angles for shading
+	bool NextCol(int *x);
+	bool IsInRange(int x, int y);
+	bool BoundRec(RECT *rec);
+	char *RangeDesc(void *d, int style);	//d points to a DataObj class
+
+private:
+	char *txt;
+	int x1, y1, x2, y2, cx, cy, curridx;
+
+	bool Reset();
+	bool Parse(int start);
+};
+
+class Triangle {
+public:
+	Triangle *next;
+	fPOINT3D pt[4];
+
+	void SetRect();
+	bool TestVertex(double x, double y);
+
+private:
+	double cx, cy, r2;				//circumcircle
+	fRECT rc;						//bounding rectangle
+	lfPOINT ld[3];					//line eqations
+};
+
+class Triangulate {
+public:
+	Triangle *trl;
+
+	Triangulate(Triangle *t_list);
+	bool AddEdge(fPOINT3D *p1, fPOINT3D *p2);
+	bool AddVertex(fPOINT3D *v);
+
+private:
+	typedef struct edge {
+		edge *next;
+		fPOINT3D p1, p2;
+	};
+	edge *edges;
+};
+
+class anyOutput{
+public:
+	int units;							//use units mm, inch ...
+	int MrkMode;						//existing mark on screen
+	void *MrkRect;						//pointer to e.g. the marked rectangle
+	fRECT Box1;							//User drawing rectangle
+	lfPOINT Box1z;						// add 3D to Box1
+	RECT DeskRect;						//this is maximum size Rectangle
+	double ddx, ddy, ddz;				//convert to device coordinates
+	double hres, vres;					//resolution in dpi
+	double LineWidth;					//line width in units
+	int iLine;							//current width of line in pixels
+	DWORD dLineCol;						//current color of line;
+	DWORD dBgCol;						//color of background
+	DWORD dFillCol, dFillCol2;
+	DWORD dPattern;						//current line bit-pattern
+	TextDEF TxtSet;						//store current text settings here
+	RunLinePat RLP;						//continuous setings of pattern line
+	AxisDEF xAxis, yAxis, zAxis;		//axis and transform definitions
+	lfPOINT VPorg;						//zoom origin
+	double VPscale;						//zoom factor
+	int MenuHeight;						//ofset due to pull down menus
+	int cCursor;						//mouse coursor identifier
+	double rotM[3][3];					//rotation matrix for 3D
+	fPOINT3D rotC;						//rotation center
+	bool hasHistMenu;					//File History List
+	int HistMenuSize;					//     -"-
+	lfPOINT light_source;				//angles for shading
 	double light_vec[3][3];				//     -"-
-	double disp_x, disp_y;				//displacement on page
-
-	anyOutput();
-	void SetRect(fRECT rec, int units, AxisDEF *x_ax, AxisDEF *y_ax);
-	void SetSpace(fPOINT3D*,fPOINT3D*,int,double*,fPOINT3D*,AxisDEF*,AxisDEF*,AxisDEF*);
-	void LightSource(double x, double y);
-	DWORD VecColor(double *plane_vec, DWORD col1, DWORD col2);
-	bool GetSize(RECT *rc);
-	virtual bool ActualSize(RECT *rc) {return GetSize(rc);};
-	double fx2fix(double x);
-	int fx2ix(double x){return (int)(0.5 + fx2fix(x));};
-	double fy2fiy(double y);
-	int fy2iy(double y){return (int)(0.5 + fy2fiy(y));};
-	bool fp2fip(lfPOINT *fdp, lfPOINT *fip);
-	bool fvec2ivec(fPOINT3D *v, fPOINT3D *iv);
-	bool cvec2ivec(fPOINT3D *v, fPOINT3D *iv);
-	bool uvec2ivec(fPOINT3D *v, fPOINT3D *iv);
-	double un2fix(double x);
-	int un2ix(double x) {return (int)(0.5 + un2fix(x));};
-	int co2ix(double x) {return un2ix(x) + iround(VPorg.fx);};
-	double co2fix(double x) {return un2fix(x) + VPorg.fx;};
-	double un2fiy(double y);
-	int un2iy(double y) {return (int)(0.5 + un2fiy(y));};
-	int co2iy(double y) {return un2iy(y) + iround(VPorg.fy);};
-	double co2fiy(double y) {return un2fiy(y) + VPorg.fy;};
-	double un2fiz(double z);
-	double fz2fiz(double z);
-	double fix2un(double fix);
-	double fiy2un(double fiy);
-	virtual bool SetLine(LineDEF *lDef){return false;};
+	double disp_x, disp_y;				//displacement on page
+
+	anyOutput();
+	void SetRect(fRECT rec, int units, AxisDEF *x_ax, AxisDEF *y_ax);
+	void SetSpace(fPOINT3D*,fPOINT3D*,int,double*,fPOINT3D*,AxisDEF*,AxisDEF*,AxisDEF*);
+	void LightSource(double x, double y);
+	DWORD VecColor(double *plane_vec, DWORD col1, DWORD col2);
+	bool GetSize(RECT *rc);
+	virtual bool ActualSize(RECT *rc) {return GetSize(rc);};
+	double fx2fix(double x);
+	int fx2ix(double x){return (int)(0.5 + fx2fix(x));};
+	double fy2fiy(double y);
+	int fy2iy(double y){return (int)(0.5 + fy2fiy(y));};
+	bool fp2fip(lfPOINT *fdp, lfPOINT *fip);
+	bool fvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+	bool cvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+	bool uvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+	double un2fix(double x);
+	int un2ix(double x) {return (int)(0.5 + un2fix(x));};
+	int co2ix(double x) {return un2ix(x) + iround(VPorg.fx);};
+	double co2fix(double x) {return un2fix(x) + VPorg.fx;};
+	double un2fiy(double y);
+	int un2iy(double y) {return (int)(0.5 + un2fiy(y));};
+	int co2iy(double y) {return un2iy(y) + iround(VPorg.fy);};
+	double co2fiy(double y) {return un2fiy(y) + VPorg.fy;};
+	double un2fiz(double z);
+	double fz2fiz(double z);
+	double fix2un(double fix);
+	double fiy2un(double fiy);
+	virtual bool SetLine(LineDEF *lDef){return false;};
 	bool GetLine(LineDEF *lDef);
-	virtual void Focus() {return;};
-	virtual void Caption(char *txt){return;};
-	virtual void MouseCursor(int cid, bool force){return;};
-	virtual bool SetScroll(bool, int, int, int, int){return false;};
-	virtual bool SetFill(FillDEF *fill){return false;};
-	virtual bool SetTextSpec(TextDEF *set);
-	virtual bool Erase(DWORD Color){return false;};
-	virtual bool StartPage(){return false;};
-	virtual bool EndPage(){return false;};
-	virtual bool Eject() {return false;};		//printers only
-	virtual bool UpdateRect(RECT *rc, bool invert){return false;};
-	virtual bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
-		int sw, int sh, bool invert){return false;};
-	virtual void ShowBitmap(int x, int y, anyOutput* src){return;};
-	bool ShowMark(void *rc, int Mode);
-	bool HideMark();
-	int CalcCursorPos(char *txt, POINT p, POINT *fit);
-	bool TextCursor(char *txt, POINT p, POINT *fit, int *pos, int disp);
-	bool PatLine(POINT p1, POINT p2);
-	virtual void ShowLine(POINT * pts, int cp, DWORD color) {return;};
-	virtual void ShowEllipse(POINT p1, POINT p2, DWORD color){return;}; 
-	virtual bool SetMenu(int type){return false;};
-	virtual void CheckMenu(int mid, bool check){return;};
-	virtual void FileHistory(){return;};
-	virtual bool oGetPix(int x, int y, DWORD *col){return false;};
-	virtual bool oDrawIcon(int type, int x, int y) {return false;};
-	virtual bool oGetTextExtent(char *text, int cb, int *width, int *height);
-	virtual bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
-	virtual bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
-	virtual bool oPolyline(POINT * pts, int cp, char *nam = 0L){return false;};
-	virtual bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
-	virtual bool oSolidLine(POINT *p){return false;};
-	virtual bool oTextOut(int x, int y, char *txt, int cb){return false;};
-	virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
-	virtual bool oArc(int x1, int y1, int x2, int y2, int quads){return false;};
-};
-
+	virtual void Focus() {return;};
+	virtual void Caption(char *txt){return;};
+	virtual void MouseCursor(int cid, bool force){return;};
+	virtual bool SetScroll(bool, int, int, int, int){return false;};
+	virtual bool SetFill(FillDEF *fill){return false;};
+	virtual bool SetTextSpec(TextDEF *set);
+	virtual bool Erase(DWORD Color){return false;};
+	virtual bool StartPage(){return false;};
+	virtual bool EndPage(){return false;};
+	virtual bool Eject() {return false;};		//printers only
+	virtual bool UpdateRect(RECT *rc, bool invert){return false;};
+	virtual bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+		int sw, int sh, bool invert){return false;};
+	virtual void ShowBitmap(int x, int y, anyOutput* src){return;};
+	bool ShowMark(void *rc, int Mode);
+	bool HideMark();
+	int CalcCursorPos(char *txt, POINT p, POINT *fit);
+	bool TextCursor(char *txt, POINT p, POINT *fit, int *pos, int disp);
+	bool PatLine(POINT p1, POINT p2);
+	virtual void ShowLine(POINT * pts, int cp, DWORD color) {return;};
+	virtual void ShowEllipse(POINT p1, POINT p2, DWORD color){return;}; 
+	virtual bool SetMenu(int type){return false;};
+	virtual void CheckMenu(int mid, bool check){return;};
+	virtual void FileHistory(){return;};
+	virtual bool oGetPix(int x, int y, DWORD *col){return false;};
+	virtual bool oDrawIcon(int type, int x, int y) {return false;};
+	virtual bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	virtual bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
+	virtual bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
+	virtual bool oPolyline(POINT * pts, int cp, char *nam = 0L){return false;};
+	virtual bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
+	virtual bool oSolidLine(POINT *p){return false;};
+	virtual bool oTextOut(int x, int y, char *txt, int cb){return false;};
+	virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
+	virtual bool oArc(int x1, int y1, int x2, int y2, int quads){return false;};
+};
+
 enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BOOL, 
-	ET_DATE, ET_TIME, ET_DATETIME, ET_BUSY=0x100, ET_CIRCULAR=0x200};
+	ET_DATE, ET_TIME, ET_DATETIME, ET_BUSY=0x100, ET_CIRCULAR=0x200, ET_EMPTY=0x400, 
+	ET_NODRAW=0x800, ET_NODRAW_EMPTY=0xc00};
 
-class EditText {
-public:
-	char *text, *ftext;
-	int Align, type, row, col;
+class EditText {
+public:
+	char *text, *ftext;
+	int Align, type, row, col;
 	void *parent;				//points to a data object: defined below
-	anyOutput *disp;
+	anyOutput *disp;
 	double Value;
-
-	EditText(void *par, char *msg, int r, int c);
-	~EditText();
-	bool AddChar(int c, anyOutput *Out, void *data_obj);
-	void Update(int select, anyOutput *Out, POINT *MousePos);
-	bool Redraw(anyOutput *Out, bool display);
-	void Mark(anyOutput *Out, int mark);
-	bool Command(int cmd, anyOutput *Out, void *data_obj);
-	bool GetValue(double *v);
+
+	EditText(void *par, char *msg, int r, int c);
+	~EditText();
+	bool AddChar(int c, anyOutput *Out, void *data_obj);
+	void Update(int select, anyOutput *Out, POINT *MousePos);
+	bool Redraw(anyOutput *Out, bool display);
+	void Mark(anyOutput *Out, int mark);
+	bool Command(int cmd, anyOutput *Out, void *data_obj);
+	bool GetValue(double *v);
 	bool GetText(char *t, int size, bool bTranslate);
-	bool GetResult(anyResult *r, bool use_last = false);
-	bool SetValue(double v);
-	bool SetText(char *t);
-	void SetRec(RECT *rc);
-	int GetX() {return loc.x;};
+	bool GetResult(anyResult *r, bool use_last = false);
+	bool SetValue(double v);
+	bool SetText(char *t);
+	void SetRec(RECT *rc);
+	int GetX() {return loc.x;};
 	int GetY() {return loc.y;};
-	int Cursor() {return CursorPos;};
-	bool isValue();
-	bool isFormula();
-	bool isInRect(POINT *p) {return (p->x>loc.x && p->x<crb.x && p->y>loc.y && p->y<rb.y);};
+	int GetRX() {return crb.x;};
+	int GetRY() {return crb.y;};
+	int Cursor() {return CursorPos;};
+	bool isValue();
+	bool isFormula();
+	bool isInRect(POINT *p) {return (p->x>loc.x && p->x<crb.x && p->y>loc.y && p->y<rb.y);};
 	bool hasMark() {return (m1 != m2 && m1 >= 0 && m2 >= 0);};
-
-private:
-	LineDEF *bgLine;
-	FillDEF *bgFill;
-	int length, CursorPos, m1, m2, mx1, mx2;
-	POINT loc, rb, crb;
-	DWORD TextCol;
-
-	void FindType();
-};
+
+private:
+	LineDEF *bgLine;
+	FillDEF *bgFill;
+	int length, CursorPos, m1, m2, mx1, mx2;
+	POINT loc, rb, crb;
+	DWORD TextCol;
+
+	void FindType();
+	void set_etracc();
+};
 
 class fmtText {
 
@@ -489,6 +538,7 @@ typedef struct _fmt_txt_info {
 }fmt_txt_info;
 
 public:
+	fmtText();
 	fmtText(anyOutput *o, int x, int y, char *txt);
 	~fmtText();
 	bool StyleAt(int idx,  TextDEF *txt_def, int *style, int *font);
@@ -499,6 +549,7 @@ public:
 	bool oGetTextExtent(anyOutput *o, int *width, int *height, int cb);
 	void SetText(anyOutput *o, char *txt, int *px, int *py);
 	void DrawText(anyOutput *o);
+	void EditMode(bool bEdit);
 
 private:
 	bool SetTextDef(TextDEF *td, int idx);
@@ -509,41 +560,66 @@ private:
 	char *src;
 	POINT pos;
 	int n_split;
+	DWORD flags;
 	fmt_txt_info *split_text;
 };
-
-class DataObj{
-public:
-	int cRows, cCols;
-	EditText ***etRows;
-
-	DataObj();
-	~DataObj();
-	virtual bool Init(int nRows, int nCols);
-	virtual bool SetValue(int row, int col, double val);
+
+class RangeInfo {
+public:
+	int col_width, row_height, first_width;
+	RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next);
+	RangeInfo(int sel, char *range, RangeInfo *next);
+	~RangeInfo();
+	int SetWidth(int w);
+	int SetDefWidth(int w);
+	int SetHeight(int h);
+	int SetFirstWidth(int w);
+	int GetWidth(int col);
+	int GetHeight(int row);
+	int GetFirstWidth();
+
+private:
+	int r_type;		// 0 default
+					// 1 column info
+					// 2 row info
+	RangeInfo *ri_next;
+	AccRange *ar;
+};
+
+class DataObj{
+public:
+	int cRows, cCols;
+	RangeInfo *ri;
+	EditText ***etRows;
+
+	DataObj();
+	~DataObj();
+	virtual bool Init(int nRows, int nCols);
+	virtual bool SetValue(int row, int col, double val);
 	virtual bool SetText(int row, int col, char *txt);
-	virtual bool GetValue(int row, int col, double *v);
+	virtual bool GetValue(int row, int col, double *v);
 	virtual bool GetText(int row, int col, char *txt, int len, bool bTranslate = true);
 	char ** GetTextPtr(int row, int col);
-	virtual bool GetResult(anyResult *r, int row, int col, bool use_last = false);
-	virtual bool GetSize(int *width, int *height);
-	virtual bool Select(POINT *p){return false;};
-	virtual bool WriteData(char *FileName) {return false;};
-	virtual bool AddCols(int nCols){return false;};
-	virtual bool AddRows(int nRows){return false;};
-	virtual bool ChangeSize(int nCols, int nRows, bool bUndo){return false;};
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
-	virtual bool ReadData(char *, unsigned char *, int){return false;};
+	virtual bool GetResult(anyResult *r, int row, int col, bool use_last = false);
+	virtual bool GetSize(int *width, int *height);
+	virtual bool isEmpty(int row, int col);
+	virtual bool Select(POINT *p){return false;};
+	virtual bool WriteData(char *FileName) {return false;};
+	virtual bool AddCols(int nCols){return false;};
+	virtual bool AddRows(int nRows){return false;};
+	virtual bool ChangeSize(int nCols, int nRows, bool bUndo){return false;};
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+	virtual bool ReadData(char *, unsigned char *, int){return false;};
 	virtual void FlushData();
 	bool ValueRec(RECT *rc);
-};
+};
 
 class StrData {
 public:
 	StrData(DataObj *par, RECT *rc = 0L);
 	~StrData();
 	bool GetSize(int *w, int *h);
-	void StrData::RestoreData(DataObj *dest);
+	void RestoreData(DataObj *dest);
 
 private:
 	int pw, ph;
@@ -551,1328 +627,1376 @@ private:
 	DataObj *src;
 	char ***str_data;
 };
-
-class HatchOut:public anyOutput {
-public:
-	HatchOut(anyOutput *Parent);
-	~HatchOut();
-	bool SetFill(FillDEF *fill);
-	bool StartPage();
-	bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-
-private:
-	anyOutput *out;
-	double xbase, ybase;
-	LineDEF ParLineDef, MyLineDef;
-	bool ParInit;
-	int ho, ht;
-	DWORD ParLinPat;
-	RECT UseRect;
-	struct {
-		int cx, cy, r;
-		}circ_grad;
-
-	bool PrepareParent(bool Restore);
-	bool DoHatch();
-	bool MkPolyLine(POINT *p, anyOutput *o);
-	bool HatchLine(POINT p1, POINT p2);
-	bool HatchArc(int x, int y, int r, int qad, bool start);
-	bool IsInside(POINT p);
-	void Lines000();
-	void Lines090();
-	void Lines045();
-	void Lines315();
-	void Stipple(int type);
-	void Zigzag();
-	void Combs();
-	void BricksH();
-	void BricksV();
-	void Bricks045();
-	void Bricks315();
-	void Texture1();
-	void Texture2();
-	void Arcs(int type);
-	void Waves2(int type);
-	void Herringbone();
-	void Circles();
-	void Grass();
-	void Foam();
+
+class HatchOut:public anyOutput {
+public:
+	HatchOut(anyOutput *Parent);
+	~HatchOut();
+	bool SetFill(FillDEF *fill);
+	bool StartPage();
+	bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
+	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+	anyOutput *out;
+	double xbase, ybase;
+	LineDEF ParLineDef, MyLineDef;
+	bool ParInit;
+	int ho, ht;
+	DWORD ParLinPat;
+	RECT UseRect;
+	struct {
+		int cx, cy, r;
+		}circ_grad;
+
+	bool PrepareParent(bool Restore);
+	bool DoHatch();
+	bool MkPolyLine(POINT *p, anyOutput *o);
+	bool HatchLine(POINT p1, POINT p2);
+	bool HatchArc(int x, int y, int r, int qad, bool start);
+	bool IsInside(POINT p);
+	void Lines000();
+	void Lines090();
+	void Lines045();
+	void Lines315();
+	void Stipple(int type);
+	void Zigzag();
+	void Combs();
+	void BricksH();
+	void BricksV();
+	void Bricks045();
+	void Bricks315();
+	void Texture1();
+	void Texture2();
+	void Arcs(int type);
+	void Waves2(int type);
+	void Herringbone();
+	void Circles();
+	void Grass();
+	void Foam();
 	void Recs();
-	void Hash();
-	void CircGrad();
-};
-
-class GraphObj {
-public:
-	unsigned long Id;			//accepts an identifier during read from file
-								//  it is set to an object identifier after
-								//  construction
-	GraphObj *parent;
-	DataObj *data;
-	int type, moveable;
-	RECT rDims;
-	char *name;
-
-	GraphObj(GraphObj *par, DataObj *d);
-	virtual ~GraphObj();
-	virtual double GetSize(int select);
-	virtual bool SetSize(int select, double value){return false;};
-	virtual DWORD GetColor(int select);
-	virtual bool SetColor(int select, DWORD col) {return false;};
-	virtual void DoPlot(anyOutput *target){return;};
-	virtual void DoMark(anyOutput *target, bool mark){return;};
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
-	virtual bool PropertyDlg(){return false;};
+	void Hash();
+	void CircGrad();
+};
+
+class GraphObj {
+public:
+	unsigned long Id;			//accepts an identifier during read from file
+								//  it is set to an object identifier after
+								//  construction
+	GraphObj *parent;
+	DataObj *data;
+	int type, moveable;
+	RECT rDims;
+	char *name;
+
+	GraphObj(GraphObj *par, DataObj *d);
+	virtual ~GraphObj();
+	virtual double GetSize(int select);
+	virtual bool SetSize(int select, double value){return false;};
+	virtual DWORD GetColor(int select);
+	virtual bool SetColor(int select, DWORD col) {return false;};
+	virtual void DoPlot(anyOutput *target){return;};
+	virtual void DoMark(anyOutput *target, bool mark){return;};
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+	virtual bool PropertyDlg(){return false;};
 	virtual void RegGO(void *n);
-	virtual bool FileIO(int rw) {return false;};
-	virtual void * ObjThere(int x, int y);
+	virtual bool FileIO(int rw) {return false;};
+	virtual void * ObjThere(int x, int y);
 	virtual void Track(POINT *p, anyOutput *o);
-};
-
-class ssButton:public GraphObj {
-public:
-
-	ssButton(GraphObj *par, int x, int y, int w, int h);
-	~ssButton();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *target, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-
-private:
-	bool bLBdown, bSelected, bMarked;
-	TextDEF TextDef;
-	LineDEF Line;
-	FillDEF Fill;
-};
-
-class dragHandle:public GraphObj {
-public:
-
-	dragHandle(GraphObj *par, int type);
-	~dragHandle();
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	RECT upd, drec, *minRC, *maxRC;
-	LineDEF LineDef;
-	FillDEF FillDef;
-};
-
-class dragRect:public GraphObj {
-public:
-
-	dragRect(GraphObj *par, int type);
-	~dragRect();
-	double GetSize(int select){return parent->GetSize(select);};
-	DWORD GetColor(int select){return parent->GetColor(select);};
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void*tmpl, anyOutput *o);
-	void * ObjThere(int x, int y);
-
-private:
-	dragHandle **handles;
-};
-
-class Drag3D:public GraphObj {
-public:
-	Drag3D(GraphObj *par);
-	~Drag3D();
-	double GetSize(int select){return parent->GetSize(select);};
-	void DoPlot(anyOutput *o);
-	void * ObjThere(int x, int y);
-
-private:
-	dragHandle **handles;
-};
-
-class FrmRect:public GraphObj {
-public:
-
-	FrmRect(GraphObj *par, fRECT *limRC, fRECT *cRC, fRECT *chld);
-	~FrmRect();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoMark(anyOutput *o, bool mark);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg(){return parent ? parent->Command(CMD_CONFIG, 0L, 0L) : false;};
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	RECT *minRC, *maxRC;
-	anyOutput *mo;
-	RECT mrc;
-	dragRect *drag;
-	bool swapX, swapY;
-	fRECT *limRC, *cRC, *chldRC, CurrRect;
-	LineDEF Line, FillLine;
-	FillDEF Fill;
-};
-
-class svgOptions:public GraphObj{
-public:
-	svgOptions(int src);
-	~svgOptions();
-	bool FileIO(int rw);
-
-private:
-	char *script, *svgattr;
-};
-
-class Symbol:public GraphObj{
-public:
-	int idx;
-
-	Symbol(GraphObj *par, DataObj *d, double x, double y, int which, 
-		int xc = -1, int xr = -1, int yc = -1, int yr = -1);
-	Symbol(int src);
-	~Symbol();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *target);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	lfPOINT fPos;
-	POINT *ssRef;
-	long cssRef;
-	double size;
-	LineDEF SymLine;
-	FillDEF SymFill;
-	TextDEF *SymTxt;
-};
-
-class Bubble:public GraphObj{
-public:
-	Bubble(GraphObj *par, DataObj *d, double x, double y, double s, 
-		int which, FillDEF *fill, LineDEF *outline, int xc = -1, 
-		int xr = -1, int yc = -1, int yr = -1, int sc = -1, int sr = -1);
-	Bubble(int src);
-	~Bubble();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
+	virtual double DefSize(int select);
+};
+
+class ssButton:public GraphObj {
+public:
+
+	ssButton(GraphObj *par, int x, int y, int w, int h);
+	~ssButton();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *target, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+
 private:
-	bool DoAutoscale(anyOutput *o);
-
-	lfPOINT fPos;
-	double fs;
-	LineDEF BubbleLine, BubbleFillLine;
-	FillDEF BubbleFill;
-	POINT pts[5];
-	POINT *ssRef;
-	long cssRef;
-};
-
-class Bar:public GraphObj {
-public:
-	Bar(GraphObj *par, DataObj *d, double x, double y, int which, 
-		int xc = -1, int xr = -1, int yc = -1, int yr = -1);
-	Bar(int src);
-	~Bar();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *target);
+	bool bLBdown, bSelected, bMarked;
+	TextDEF TextDef;
+	LineDEF Line;
+	FillDEF Fill;
+};
+
+class dragHandle:public GraphObj {
+public:
+
+	dragHandle(GraphObj *par, int type);
+	~dragHandle();
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	RECT upd, drec, *minRC, *maxRC;
+	LineDEF LineDef;
+	FillDEF FillDef;
+};
+
+class dragRect:public GraphObj {
+public:
+
+	dragRect(GraphObj *par, int type);
+	~dragRect();
+	double GetSize(int select){return parent->GetSize(select);};
+	DWORD GetColor(int select){return parent->GetColor(select);};
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void*tmpl, anyOutput *o);
+	void * ObjThere(int x, int y);
+
+private:
+	dragHandle **handles;
+};
+
+class Drag3D:public GraphObj {
+public:
+	Drag3D(GraphObj *par);
+	~Drag3D();
+	double GetSize(int select){return parent->GetSize(select);};
+	void DoPlot(anyOutput *o);
+	void * ObjThere(int x, int y);
+
+private:
+	dragHandle **handles;
+};
+
+class FrmRect:public GraphObj {
+public:
+
+	FrmRect(GraphObj *par, fRECT *limRC, fRECT *cRC, fRECT *chld);
+	~FrmRect();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
 	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	anyOutput *mo;
-	RECT mrc;
-	double size;
-	LineDEF BarLine, HatchLine;
-	FillDEF BarFill;
-	lfPOINT fPos, BarBase;
-	POINT *ssRef;
-	long cssRef;
-};
-
-class DataLine:public GraphObj{
-public:
-	bool isPolygon, dirty;
-	lfPOINT *Values;
-	lfPOINT min, max;
-	LineDEF LineDef;
-	long nPnt, nPntSet, cp;
-	DWORD BgColor;
-	POINT *pts;
-	char *ssXref, *ssYref;
-	anyOutput *mo;
-	RECT mrc;
-
-	DataLine(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L);
-	DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval);
-	DataLine(int src);
-	~DataLine();
-	bool SetColor(int select, DWORD col);
-	virtual void DoPlot(anyOutput *target);
-	virtual void DoMark(anyOutput *o, bool mark);
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
-	virtual bool PropertyDlg();
-	virtual bool FileIO(int rw);
-
-	void FileValues(char *name, int type, double start, double step);
-	void SetValues();
-	void LineData(lfPOINT *val, long nval);
-	void DrawCurve(anyOutput *target);
-	void DrawSpline(anyOutput *target);
-};
-
-class DataPolygon:public DataLine{
-public:
-	DataPolygon(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L);
-	DataPolygon(int src);
-	~DataPolygon();
-	void DoPlot(anyOutput *target);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	FillDEF pgFill;
-	LineDEF pgFillLine;
-};
-
-class RegLine:public GraphObj{
-public:
-	RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int type);
-	RegLine(int src);
-	~RegLine();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-	void Recalc(lfPOINT *values, long n);
-	LineDEF *GetLine(){return &LineDef;};
-
-private:
-	long nPoints, cp;
-	double mx, my;
-	LineDEF LineDef;
-	fRECT lim, uclip;
-	lfPOINT l1, l2, l3, l4, l5;
-	DWORD BgColor;
-	POINT *pts;
-};
-
-class SDellipse:public GraphObj{
-public:
-	SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel);
-	SDellipse(int src);
-	~SDellipse();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-
-	void Recalc(lfPOINT *values, long n);
-
-private:
-	long nPoints, cp;
-	double sd1, sd2, mx, my;
-	POINT *pts;
-	LineDEF LineDef;
-	fRECT lim;
-	lfPOINT *val;
-	RegLine *rl;
-};
-
-class ErrorBar:public GraphObj{
-public:
-	ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int type,
-		int xc=-1, int xr=-1, int yc=-1, int yr=-1, int ec=-1, int er=-1);
-	ErrorBar(int src);
-	~ErrorBar();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *target);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	anyOutput *mo;
-	RECT mrc;
-	lfPOINT fPos;
-	double ferr, SizeBar;
-	POINT ebpts[6];
-	LineDEF ErrLine;
-	POINT *ssRef;
-	long cssRef;
-};
-
-class Arrow:public GraphObj {
-public:
-	Arrow(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which = 0,
-		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
-		int yc2=-1, int yr2=-1);
-	Arrow(int src);
-	~Arrow();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select){return LineDef.color;};
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	dragHandle *dh1, *dh2;
-	POINT pts[5];
-	lfPOINT pos1, pos2;
-	double cw, cl;
-	LineDEF LineDef;
-	POINT *ssRef;
-	long cssRef;
-	bool bModified;
-
-	void Redraw(anyOutput *o);
-};
-
-class Box:public GraphObj {
-public:
-	Box(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which, 
-		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
-		int yc2=-1, int yr2=-1);
-	Box(int src);
-	~Box();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	double size;
-	lfPOINT pos1, pos2;
-	POINT pts[5];
-	LineDEF Outline, Hatchline;
-	FillDEF Fill;
-	POINT *ssRef;
-	long cssRef;
-};
-
-class Whisker:public GraphObj {
-public:
-	Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
-		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
-		int yc2=-1, int yr2=-1);
-	Whisker(int src);
-	~Whisker();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	anyOutput *mo;
-	RECT mrc;
-	double size;
-	POINT pts[6];
-	lfPOINT pos1, pos2;
-	LineDEF LineDef;
-	POINT *ssRef;
-	long cssRef;
-};
-
-class DropLine:public GraphObj{
-public:
-	DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc = -1, 
-		int xr = -1, int yc = -1, int yr = -1);
-	DropLine(int src);
-	~DropLine();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	lfPOINT fPos;
-	POINT pts[4];
-	LineDEF LineDef;
-	POINT *ssRef;
-	long cssRef;
-	bool bModified;
-};
-
-class line_segment:public GraphObj{
-public:
-	line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2);
-	~line_segment();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void * ObjThere(int x, int y);
-
-private:
-	LineDEF Line;
-	POINT3D **ldata;
-	fPOINT3D fmin, fmax;
-	int *nldata, nli, ndf_go;
-	double prop;
-	bool bDrawDone;
-	GraphObj *co, **df_go;
-
-	void DoClip(GraphObj *co);
-};
-
-class sph_scanline:public GraphObj{
-public:
-	int rad;
-	bool vert;
-
-	sph_scanline(POINT3D *center, int radius, bool bVert);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-
-	void DoClip(GraphObj *co);
-	bool GetPoint(POINT *p, int sel);
-
-private:
-	POINT3D p1, p2, cent;
-	bool bValid1, bValid2;
-};
-
-class Sphere:public GraphObj{
-public:
-	Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z, double r,
-		int xc = -1, int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
-		int rc = -1, int rr = -1);
-	Sphere(int src);
-	~Sphere();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	int ix, iy, rx, ry, nscl;
-	LineDEF Line;
-	FillDEF Fill;
-	fPOINT3D fPos, fip;
-	double size;
-	POINT *ssRef;
-	long cssRef;
-	GraphObj *co;
-	bool bModified, bDrawDone;
-	sph_scanline **scl;
-
-	void DoClip(GraphObj *co);
-	void DrawPG(anyOutput *o, int start);
-};
-
-class plane:public GraphObj{
-public:
-	plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line, 
-		FillDEF *fill);
-	~plane();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void * ObjThere(int x, int y);
-
-	bool GetPolygon(POINT3D **pla, int *npt, int sel);
-	double *GetVec() {return PlaneVec;};
-
-private:
-	LineDEF Line;
-	FillDEF Fill;
-	double *PlaneVec;
-	POINT3D **ldata, ReqPoint;
-	int *nldata, nli, n_ipts, n_lines;
-	POINT *ipts;
-	lfPOINT xBounds, yBounds, zBounds;
-	bool bDrawDone, bReqPoint;
-	GraphObj *co;
-	line_segment **lines;
-	long totalArea;
-
-	void DoClip(GraphObj *co);
-	bool IsValidPG(POINT3D *pg, int npg);
-};
-
-class Plane3D:public GraphObj {
-public:
-	Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt);
-	Plane3D(int src);
-	~Plane3D();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	plane *ipl;
-	fPOINT3D *dt, *pts;
-	long ndt;
-	LineDEF Line;
-	FillDEF Fill;
-};
-
-class Brick:public GraphObj{
-public:
-	Brick(GraphObj *par, DataObj *da, double x, double y, double z, 
-		double d, double w, double h, DWORD flags, int xc = -1,
-		int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
-		int dc = -1, int dr = -1, int wc = -1, int wr = -1, int hc = -1,
-		int hr = -1);
-	Brick(int src);
-	~Brick();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	LineDEF Line;
-	FillDEF Fill;
-	fPOINT3D fPos;
-	double depth, width, height;
-	DWORD flags;
-	POINT *ssRef;
-	long cssRef;
-	plane **faces;
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg(){return parent ? parent->Command(CMD_CONFIG, 0L, 0L) : false;};
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	RECT *minRC, *maxRC;
 	anyOutput *mo;
 	RECT mrc;
-	bool bModified;
-};
-
-class DropLine3D:public GraphObj{
-public:
-	DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc = -1,
-		int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1);
-	DropLine3D(int src);
-	~DropLine3D();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	line_segment *ls[6];
-	POINT mpts[6][2];
-	LineDEF Line;
-	fPOINT3D fPos;
-	POINT *ssRef;
-	long cssRef;
-	bool bModified;
-	anyOutput *mo;
-	RECT mrc;
-};
-
-class Arrow3D:public GraphObj{
-public:
-	Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1 = -1,
-		int xr1 = -1, int yc1 = -1, int yr1 = -1, int zc1 = -1, int zr1 = -1, 
-		int xc2 = -1, int xr2 = -1, int yc2 = -1, int yr2 = -1, int zc2 = -1, 
-		int zr2 = -1);
-	Arrow3D(int src);
-	~Arrow3D();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	line_segment *ls[3];
-	plane *cap;
-	double cw, cl;
-	POINT mpts[3][2];
-	LineDEF Line;
-	fPOINT3D fPos1, fPos2;
-	POINT *ssRef;
-	long cssRef;
-	bool bModified;
-};
-
-class Line3D:public GraphObj{
+	dragRect *drag;
+	bool swapX, swapY;
+	fRECT *limRC, *cRC, *chldRC, CurrRect;
+	LineDEF Line, FillLine;
+	FillDEF Fill;
+};
+
+class svgOptions:public GraphObj{
 public:
-	LineDEF Line;
-
-	Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz);
-	Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, int xc1 = -1,
-		int xr1 = -1, int yc1 = -1, int yr1 = -1, int zc1 = -1, int zr1 = -1, 
-		int xc2 = -1, int xr2 = -1, int yc2 = -1, int yr2 = -1, int zc2 = -1, 
-		int zr2 = -1);
-	Line3D(int src);
-	~Line3D();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-
-private:
-	line_segment **ls;
-	fPOINT3D *values, min, max;
-	POINT *pts;
-	long nPts, npts;
-	char *x_range, *y_range, *z_range;
+	svgOptions(int src);
+	~svgOptions();
+	bool FileIO(int rw);
+
+private:
+	char *script, *svgattr;
+};
+
+class Symbol:public GraphObj{
+public:
+	int idx;
+
+	Symbol(GraphObj *par, DataObj *d, double x, double y, int which, 
+		int xc = -1, int xr = -1, int yc = -1, int yr = -1);
+	Symbol(int src);
+	~Symbol();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *target);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	lfPOINT fPos;
 	POINT *ssRef;
 	long cssRef;
-	bool bModified;
-	anyOutput *mo;
-	RECT mrc;
-
-	void DoUpdate();
-};
-
-class Label:public GraphObj{
-public:
-	Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
-		int xc = -1, int xr = -1, int yc = -1, int yr = -1, int tc = -1, int tr = -1);
-	Label(int src);
-	~Label();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-	bool CalcRect(anyOutput *o);
-	void RedrawEdit(anyOutput *o);
-	void ShowCursor(anyOutput *o);
-	bool AddChar(int ci, anyOutput *o);
-	void CalcCursorPos(int x, int y, anyOutput *o);
-	void SetModified();
-	void DoPlotText(anyOutput *o);
-	TextDEF *GetTextDef(){return &TextDef;};
-
-private:
-	lfPOINT fPos, fDist;
-	double si, csi, curr_z;
-	DWORD flags, bgcolor;
-	TextDEF TextDef;
-	LineDEF bgLine;
-	int ix, iy, CursorPos;
-	bool is3D;
-	RECT Cursor;
-	POINT pts[5];
-	POINT *ssRef;
-	long cssRef;
-	anyOutput *defDisp;
-	bool bModified, bBGvalid;
-	fmtText *fmt_txt;
-};
-
-class mLabel:public GraphObj{
-public:
-	mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *, int, DWORD);
-	mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *);
-	mLabel(int src);
-	~mLabel();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void RegGO(void *n);
-	bool FileIO(int rw);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	lfPOINT fPos, fDist, cPos, cPos1, dist;
-	double si, csi, curr_z, lspc;
-	DWORD flags, undo_flags;
-	TextDEF TextDef;
-	long nLines;
-	int cli;
-	bool is3D;
-	Label **Lines;
-};
-
-class segment:public GraphObj{
-public:
-	segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2, double a1, double a2);
-	segment(int src);
-	~segment();
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	lfPOINT fCent;
-	long nPts;
-	double radius1, radius2, angle1, angle2, shift;
-	LineDEF segLine, segFillLine;
-	FillDEF segFill;
-	POINT *pts;
-	bool bModified;
-};
-
-class polyline:public GraphObj {
-public:
-	dragHandle **pHandles;
-	lfPOINT *Values;
-	long nPoints, nPts;
-	POINT *pts;
-	LineDEF pgLine, pgFillLine;
-	FillDEF pgFill;
-	bool bModified;
-
-	polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
-	polyline(int src);
-	~polyline();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select);
-	virtual void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	virtual bool PropertyDlg();
-	virtual bool FileIO(int rw);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	void ShowPoints(anyOutput *o);
+	double size;
+	LineDEF SymLine;
+	FillDEF SymFill;
+	TextDEF *SymTxt;
 };
 
-class Bezier:public polyline {
+class Bubble:public GraphObj{
 public:
-	Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res);
-	Bezier(int src);
+	Bubble(GraphObj *par, DataObj *d, double x, double y, double s, 
+		int which, FillDEF *fill, LineDEF *outline, int xc = -1, 
+		int xr = -1, int yc = -1, int yr = -1, int sc = -1, int sr = -1);
+	Bubble(int src);
+	~Bubble();
 	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
 	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	bool FileIO(int rw);
 
 private:
-	void AddPoints(int n, lfPOINT *p);
+	bool DoAutoscale(anyOutput *o);
 
-	void FitCurve(lfPOINT *d, int npt, double error);
-	void FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error);
-	void RemovePoint(lfPOINT *d, int sel);
-	void GenerateBezier(lfPOINT *d, int first, int last, double * uPrime, lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve);
-	double *Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve);
-	lfPOINT fBezier(int degree, lfPOINT *V, double t);
-	double * ChordLengthParameterize(lfPOINT *d, int first, int last);
-	double ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint);
+	lfPOINT fPos;
+	double fs;
+	LineDEF BubbleLine, BubbleFillLine;
+	FillDEF BubbleFill;
+	POINT pts[5];
+	POINT *ssRef;
+	long cssRef;
 };
-
-class polygon:public polyline {
-public:
-	polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
-	polygon(int src):polyline(src){};
-	bool PropertyDlg();
-};
-
-class rectangle:public GraphObj {
-public:
-	lfPOINT fp1, fp2;
-	LineDEF Line, FillLine;
-	FillDEF Fill;
-	double rad;
-	bool bModified;
-
-	rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
-	rectangle(int src);
-	~rectangle();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select){return Line.color;};
-	void DoMark(anyOutput *o, bool mark);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-
-private:
-	POINT *pts;
-	long nPts;
-	dragRect *drc;
-	void PlotRoundRect(anyOutput *o);
-};
-
-class ellipse:public rectangle {
-public:
-	ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
-	ellipse(int src);
-};
-
-class roundrec:public rectangle {
-public:
-	roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
-	roundrec(int src);
-};
-
-class LegItem:public GraphObj{
-public:
-	DWORD flags;
 
-	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill);
-	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
-	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc);
-	LegItem(int src);
-	~LegItem();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void RegGO(void *n);
-	bool FileIO(int rw);
-	void Track(POINT *p, anyOutput *o);
-
-	bool HasFill(LineDEF *ld, FillDEF *fd);
-	bool HasSym(LineDEF *ld, GraphObj *sy);
-	bool HasErr(LineDEF *ld, int err);
-
-private:
-	LineDEF DataLine, OutLine, HatchLine;
-	FillDEF Fill;
-	Symbol *Sym;
-	Label *Desc;
-	RECT hcr;
-
-	void DefDesc(char *txt);
-};
-
-class Legend:public GraphObj{
-public:
-	Legend(GraphObj *par, DataObj *d);
-	Legend(int src);
-	~Legend();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void RegGO(void *n);
-	bool FileIO(int rw);
-	void Track(POINT *p, anyOutput *o);
-
-	bool HasFill(LineDEF *ld, FillDEF *fd);
-	bool HasSym(LineDEF *ld, GraphObj *sy);
-	bool HasErr(LineDEF *ld, int err, char *desc);
-
-private:
-	lfPOINT pos, lb_pos;
-	RECT trc;
-	anyOutput *to;
-	fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
-	long nItems;
-	bool hasLine;
-	LegItem **Items;
-};
-
-class Plot:public GraphObj{
-public:
-	fRECT Bounds;					//contains minima and maxima for x and y
-	bool dirty;						//rescale before redraw;
-	int use_xaxis, use_yaxis;		//this plot uses its own axes
-	lfPOINT xBounds, yBounds, zBounds;	//like Bounds but in 3D space
-	int hidden;						//plot (layer) is not visible
-
-	Plot(GraphObj *par, DataObj *d);
-	virtual double GetSize(int select);
-	virtual bool SetSize(int select, double value){return false;};
-	virtual DWORD GetColor(int select);
-	virtual bool SetColor(int select, DWORD col){return false;};
-	virtual void DoPlot(anyOutput *o){return;};
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
-	virtual bool PropertyDlg(){return false;};
-
-	void CheckBounds(double x, double y);
-	bool UseAxis(int idx);
-	void ApplyAxes(anyOutput *o);
-	void CheckBounds3D(double x, double y, double z);
-	bool SavVarObs(GraphObj **gol, long ngo, DWORD flags);
-	DataObj *CreaCumData(char *xr, char *yr, int mode, double base);
-};
-
-class PlotScatt:public Plot{
-public:
-	char *xRange, *yRange;
-	long nPoints;
-	int DefSym;
-	lfPOINT BarDist;
-	Bar **Bars;
-	Symbol **Symbols;
-	DataLine *TheLine;
-	ErrorBar **Errors;
-	Label **Labels;
+class Bar:public GraphObj {
+public:
+	Bar(GraphObj *par, DataObj *d, double x, double y, int which, 
+		int xc = -1, int xr = -1, int yc = -1, int yr = -1, char *desc = 0L);
+	Bar(int src);
+	~Bar();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *target);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
 
-	PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
-	PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars);
-	PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin);
-	PlotScatt(int src);
-	~PlotScatt();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *target);
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
-	virtual bool PropertyDlg();
-	void RegGO(void *n);
-	virtual bool FileIO(int rw);
+private:
+	anyOutput *mo;
+	RECT mrc;
+	double size;
+	LineDEF BarLine, HatchLine;
+	FillDEF BarFill;
+	lfPOINT fPos, BarBase;
+	POINT *ssRef;
+	long cssRef;
+};
 
-	bool ForEach(int cmd, void *tmp, anyOutput *o);
-
-private:
-	DWORD DefSel;
-	char *ErrRange, *LbRange;
-	Arrow **Arrows;
-	DropLine **DropLines;
-
-	bool CreateBarChart();
+class DataLine:public GraphObj{
+public:
+	bool isPolygon, dirty;
+	lfPOINT *Values;
+	lfPOINT min, max;
+	LineDEF LineDef;
+	long nPnt, nPntSet, cp;
+	DWORD BgColor;
+	POINT *pts;
+	char *ssXref, *ssYref;
+	anyOutput *mo;
+	RECT mrc;
+
+	DataLine(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L, char *name=0L);
+	DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *name);
+	DataLine(int src);
+	~DataLine();
+	bool SetColor(int select, DWORD col);
+	virtual void DoPlot(anyOutput *target);
+	virtual void DoMark(anyOutput *o, bool mark);
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+	virtual bool PropertyDlg();
+	virtual bool FileIO(int rw);
+
+	void FileValues(char *name, int type, double start, double step);
+	void SetValues();
+	void LineData(lfPOINT *val, long nval);
+	void DrawCurve(anyOutput *target);
+	void DrawSpline(anyOutput *target);
+};
+
+class DataPolygon:public DataLine{
+public:
+	DataPolygon(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L, char *name=0L);
+	DataPolygon(int src);
+	~DataPolygon();
+	void DoPlot(anyOutput *target);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	FillDEF pgFill;
+	LineDEF pgFillLine;
+};
+
+class RegLine:public GraphObj{
+public:
+	RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int type);
+	RegLine(int src);
+	~RegLine();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+	void Recalc(lfPOINT *values, long n);
+	LineDEF *GetLine(){return &LineDef;};
+
+private:
+	long nPoints, cp;
+	double mx, my;
+	LineDEF LineDef;
+	fRECT lim, uclip;
+	lfPOINT l1, l2, l3, l4, l5;
+	DWORD BgColor;
+	POINT *pts;
+};
+
+class SDellipse:public GraphObj{
+public:
+	SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel);
+	SDellipse(int src);
+	~SDellipse();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+	void Recalc(lfPOINT *values, long n);
+
+private:
+	long nPoints, cp;
+	double sd1, sd2, mx, my;
+	POINT *pts;
+	LineDEF LineDef;
+	fRECT lim;
+	lfPOINT *val;
+	RegLine *rl;
+};
+
+class ErrorBar:public GraphObj{
+public:
+	ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int type,
+		int xc=-1, int xr=-1, int yc=-1, int yr=-1, int ec=-1, int er=-1);
+	ErrorBar(int src);
+	~ErrorBar();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *target);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	anyOutput *mo;
+	RECT mrc;
+	lfPOINT fPos;
+	double ferr, SizeBar;
+	POINT ebpts[6];
+	LineDEF ErrLine;
+	POINT *ssRef;
+	long cssRef;
+};
+
+class Arrow:public GraphObj {
+public:
+	Arrow(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which = 0,
+		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+		int yc2=-1, int yr2=-1);
+	Arrow(int src);
+	~Arrow();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select){return LineDef.color;};
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	dragHandle *dh1, *dh2;
+	POINT pts[5];
+	lfPOINT pos1, pos2;
+	double cw, cl;
+	LineDEF LineDef;
+	POINT *ssRef;
+	long cssRef;
+	bool bModified;
+
+	void Redraw(anyOutput *o);
+};
+
+class Box:public GraphObj {
+public:
+	Box(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which, 
+		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+		int yc2=-1, int yr2=-1);
+	Box(int src);
+	~Box();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	double size;
+	lfPOINT pos1, pos2;
+	POINT pts[5];
+	LineDEF Outline, Hatchline;
+	FillDEF Fill;
+	POINT *ssRef;
+	long cssRef;
+};
+
+class Whisker:public GraphObj {
+public:
+	Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+		int yc2=-1, int yr2=-1);
+	Whisker(int src);
+	~Whisker();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	anyOutput *mo;
+	RECT mrc;
+	double size;
+	POINT pts[6];
+	lfPOINT pos1, pos2;
+	LineDEF LineDef;
+	POINT *ssRef;
+	long cssRef;
+};
+
+class DropLine:public GraphObj{
+public:
+	DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc = -1, 
+		int xr = -1, int yc = -1, int yr = -1);
+	DropLine(int src);
+	~DropLine();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	lfPOINT fPos;
+	POINT pts[4];
+	LineDEF LineDef;
+	POINT *ssRef;
+	long cssRef;
+	bool bModified;
+};
+
+class line_segment:public GraphObj{
+public:
+	line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2);
+	~line_segment();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void * ObjThere(int x, int y);
+
+private:
+	LineDEF Line;
+	POINT3D **ldata;
+	fPOINT3D fmin, fmax;
+	int *nldata, nli, ndf_go;
+	double prop;
+	bool bDrawDone;
+	GraphObj *co, **df_go;
+
+	void DoClip(GraphObj *co);
+};
+
+class sph_scanline:public GraphObj{
+public:
+	int rad;
+	bool vert;
+
+	sph_scanline(POINT3D *center, int radius, bool bVert);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+
+	void DoClip(GraphObj *co);
+	bool GetPoint(POINT *p, int sel);
+
+private:
+	POINT3D p1, p2, cent;
+	bool bValid1, bValid2;
+};
+
+class Sphere:public GraphObj{
+public:
+	Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z, double r,
+		int xc = -1, int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
+		int rc = -1, int rr = -1);
+	Sphere(int src);
+	~Sphere();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	int ix, iy, rx, ry, nscl;
+	LineDEF Line;
+	FillDEF Fill;
+	fPOINT3D fPos, fip;
+	double size;
+	POINT *ssRef;
+	long cssRef;
+	GraphObj *co;
+	bool bModified, bDrawDone;
+	sph_scanline **scl;
+
+	void DoClip(GraphObj *co);
+	void DrawPG(anyOutput *o, int start);
+};
+
+class plane:public GraphObj{
+public:
+	plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line, 
+		FillDEF *fill);
+	~plane();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void * ObjThere(int x, int y);
+
+	bool GetPolygon(POINT3D **pla, int *npt, int sel);
+	double *GetVec() {return PlaneVec;};
+
+private:
+	LineDEF Line;
+	FillDEF Fill;
+	double *PlaneVec;
+	POINT3D **ldata, ReqPoint;
+	int *nldata, nli, n_ipts, n_lines;
+	POINT *ipts;
+	lfPOINT xBounds, yBounds, zBounds;
+	bool bDrawDone, bReqPoint;
+	GraphObj *co;
+	line_segment **lines;
+	long totalArea;
+
+	void DoClip(GraphObj *co);
+	bool IsValidPG(POINT3D *pg, int npg);
+};
+
+class Plane3D:public GraphObj {
+public:
+	Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt);
+	Plane3D(int src);
+	~Plane3D();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	plane *ipl;
+	fPOINT3D *dt, *pts;
+	long ndt;
+	LineDEF Line;
+	FillDEF Fill;
+};
+
+class Brick:public GraphObj{
+public:
+	Brick(GraphObj *par, DataObj *da, double x, double y, double z, 
+		double d, double w, double h, DWORD flags, int xc = -1,
+		int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
+		int dc = -1, int dr = -1, int wc = -1, int wr = -1, int hc = -1,
+		int hr = -1);
+	Brick(int src);
+	~Brick();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	LineDEF Line;
+	FillDEF Fill;
+	fPOINT3D fPos;
+	double depth, width, height;
+	DWORD flags;
+	POINT *ssRef;
+	long cssRef;
+	plane **faces;
+	anyOutput *mo;
+	RECT mrc;
+	bool bModified;
+};
+
+class DropLine3D:public GraphObj{
+public:
+	DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc = -1,
+		int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1);
+	DropLine3D(int src);
+	~DropLine3D();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	line_segment *ls[6];
+	POINT mpts[6][2];
+	LineDEF Line;
+	fPOINT3D fPos;
+	POINT *ssRef;
+	long cssRef;
+	bool bModified;
+	anyOutput *mo;
+	RECT mrc;
+};
+
+class Arrow3D:public GraphObj{
+public:
+	Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1 = -1,
+		int xr1 = -1, int yc1 = -1, int yr1 = -1, int zc1 = -1, int zr1 = -1, 
+		int xc2 = -1, int xr2 = -1, int yc2 = -1, int yr2 = -1, int zc2 = -1, 
+		int zr2 = -1);
+	Arrow3D(int src);
+	~Arrow3D();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	line_segment *ls[3];
+	plane *cap;
+	double cw, cl;
+	POINT mpts[3][2];
+	LineDEF Line;
+	fPOINT3D fPos1, fPos2;
+	POINT *ssRef;
+	long cssRef;
+	bool bModified;
+};
+
+class Line3D:public GraphObj{
+public:
+	LineDEF Line;
+
+	Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz);
+	Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, int xc1 = -1,
+		int xr1 = -1, int yc1 = -1, int yr1 = -1, int zc1 = -1, int zr1 = -1, 
+		int xc2 = -1, int xr2 = -1, int yc2 = -1, int yr2 = -1, int zc2 = -1, 
+		int zr2 = -1);
+	Line3D(int src);
+	~Line3D();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	line_segment **ls;
+	fPOINT3D *values, min, max;
+	POINT *pts;
+	long nPts, npts;
+	char *x_range, *y_range, *z_range;
+	POINT *ssRef;
+	long cssRef;
+	bool bModified;
+	anyOutput *mo;
+	RECT mrc;
+
+	void DoUpdate();
+};
+
+class Label:public GraphObj{
+public:
+	Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
+		int xc = -1, int xr = -1, int yc = -1, int yr = -1, int tc = -1, int tr = -1);
+	Label(int src);
+	~Label();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+	bool CalcRect(anyOutput *o);
+	void RedrawEdit(anyOutput *o);
+	void ShowCursor(anyOutput *o);
+	bool AddChar(int ci, anyOutput *o);
+	void CalcCursorPos(int x, int y, anyOutput *o);
+	void SetModified();
+	void DoPlotText(anyOutput *o);
+	TextDEF *GetTextDef(){return &TextDef;};
+
+private:
+	lfPOINT fPos, fDist;
+	double si, csi, curr_z;
+	DWORD flags, bgcolor;
+	TextDEF TextDef;
+	LineDEF bgLine;
+	int ix, iy, CursorPos;
+	bool is3D;
+	RECT Cursor;
+	POINT pts[5];
+	POINT *ssRef;
+	long cssRef;
+	anyOutput *defDisp;
+	bool bModified, bBGvalid;
+	fmtText *fmt_txt;
+};
+
+class mLabel:public GraphObj{
+public:
+	mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *, int, DWORD);
+	mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *);
+	mLabel(int src);
+	~mLabel();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void RegGO(void *n);
+	bool FileIO(int rw);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	lfPOINT fPos, fDist, cPos, cPos1, dist;
+	double si, csi, curr_z, lspc;
+	DWORD flags, undo_flags;
+	TextDEF TextDef;
+	long nLines;
+	int cli;
+	bool is3D;
+	Label **Lines;
+};
+
+class TextFrame:public GraphObj{
+	enum {TF_MAXLINE=120};
+public:
+	TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt);
+	TextFrame(int src);
+	~TextFrame();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	void DoMark(anyOutput *o, bool mark);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	fRECT pad;
+	RECT ipad, Cursor, *tm_rec;
+	fmtText fmt_txt;
+	int nlines, linc, tm_c, csize, cpos;
+	bool bModified, bResize, has_m1, has_m2;
+	unsigned char c_char, m1_char, m2_char;
+	double lspc;
+	lfPOINT pos1, pos2;
+	POINT cur_pos, m1_pos, m2_pos, m1_cpos, m2_cpos;
+	TextDEF TextDef;
+	dragRect *drc;
+	unsigned char *text, **lines;
+	LineDEF Line, FillLine;
+	FillDEF Fill;
+
+	void text2lines(anyOutput *o);
+	void lines2text();
+	void ShowCursor(anyOutput *o);
+	void AddChar(anyOutput *o, unsigned char c);
+	void DelChar(anyOutput *o);
+	void CalcCursorPos(int x, int y, anyOutput *o);
+	void ReplMark(anyOutput *o, char *ntext);
+	void procTokens();
+	bool DoPaste(anyOutput *o);
+	void TextMark(anyOutput *o, int mode);
+	bool CopyText(anyOutput *o, bool b_cut);
+};
+
+class segment:public GraphObj{
+public:
+	segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2, double a1, double a2);
+	segment(int src);
+	~segment();
+	bool SetSize(int select, double value);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	lfPOINT fCent;
+	long nPts;
+	double radius1, radius2, angle1, angle2, shift;
+	LineDEF segLine, segFillLine;
+	FillDEF segFill;
+	POINT *pts;
+	bool bModified;
+};
+
+class polyline:public GraphObj {
+public:
+	dragHandle **pHandles;
+	lfPOINT *Values;
+	long nPoints, nPts;
+	POINT *pts;
+	LineDEF pgLine, pgFillLine;
+	FillDEF pgFill;
+	bool bModified;
+
+	polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
+	polyline(int src);
+	~polyline();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select);
+	virtual void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	virtual bool PropertyDlg();
+	virtual bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	void ShowPoints(anyOutput *o);
+};
+
+class Bezier:public polyline {
+public:
+	Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res);
+	Bezier(int src);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool FileIO(int rw);
+
+private:
+	void AddPoints(int n, lfPOINT *p);
+
+	void FitCurve(lfPOINT *d, int npt, double error);
+	void IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2);
+	void FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error);
+	void RemovePoint(lfPOINT *d, int sel);
+	void GenerateBezier(lfPOINT *d, int first, int last, double * uPrime, lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve);
+	double *Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve);
+	lfPOINT fBezier(int degree, lfPOINT *V, double t);
+	double *ChordLengthParameterize(lfPOINT *d, int first, int last);
+	double ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint);
+};
+
+class polygon:public polyline {
+public:
+	polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
+	polygon(int src):polyline(src){};
+	bool PropertyDlg();
+};
+
+class rectangle:public GraphObj {
+public:
+	lfPOINT fp1, fp2;
+	LineDEF Line, FillLine;
+	FillDEF Fill;
+	double rad;
+	bool bModified;
+
+	rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+	rectangle(int src);
+	~rectangle();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select){return Line.color;};
+	void DoMark(anyOutput *o, bool mark);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+
+private:
+	POINT *pts;
+	long nPts;
+	dragRect *drc;
+	void PlotRoundRect(anyOutput *o);
+};
+
+class ellipse:public rectangle {
+public:
+	ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+	ellipse(int src);
+};
+
+class roundrec:public rectangle {
+public:
+	roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+	roundrec(int src);
+};
+
+class LegItem:public GraphObj{
+public:
+	DWORD flags;
+
+	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill, char *desc);
+	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
+	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc);
+	LegItem(int src);
+	~LegItem();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void RegGO(void *n);
+	bool FileIO(int rw);
+	void Track(POINT *p, anyOutput *o);
+
+	bool HasFill(LineDEF *ld, FillDEF *fd, char *desc);
+	bool HasSym(LineDEF *ld, GraphObj *sy);
+	bool HasErr(LineDEF *ld, int err);
+
+private:
+	LineDEF DataLine, OutLine, HatchLine;
+	FillDEF Fill;
+	Symbol *Sym;
+	Label *Desc;
+	RECT hcr;
+
+	void DefDesc(char *txt);
+};
+
+class Legend:public GraphObj{
+public:
+	Legend(GraphObj *par, DataObj *d);
+	Legend(int src);
+	~Legend();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	void RegGO(void *n);
+	bool FileIO(int rw);
+	void Track(POINT *p, anyOutput *o);
+
+	bool HasFill(LineDEF *ld, FillDEF *fd, char *desc);
+	bool HasSym(LineDEF *ld, GraphObj *sy, char *desc);
+	bool HasErr(LineDEF *ld, int err, char *desc);
+
+private:
+	lfPOINT pos, lb_pos;
+	RECT trc;
+	anyOutput *to;
+	fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
+	long nItems;
+	bool hasLine;
+	LegItem **Items;
+};
+
+class Plot:public GraphObj{
+public:
+	fRECT Bounds;					//contains minima and maxima for x and y
+	bool dirty;						//rescale before redraw;
+	int use_xaxis, use_yaxis;		//this plot uses its own axes
+	lfPOINT xBounds, yBounds, zBounds;	//like Bounds but in 3D space
+	int hidden;						//plot (layer) is not visible
+	char *x_info, *y_info, *z_info;	//descriptor used e.g. for axis label or legend
+
+	Plot(GraphObj *par, DataObj *d);
+	virtual double GetSize(int select);
+	virtual bool SetSize(int select, double value){return false;};
+	virtual DWORD GetColor(int select);
+	virtual bool SetColor(int select, DWORD col){return false;};
+	virtual void DoPlot(anyOutput *o){return;};
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+	virtual bool PropertyDlg(){return false;};
+
+	void CheckBounds(double x, double y);
+	bool UseAxis(int idx);
+	void ApplyAxes(anyOutput *o);
+	void CheckBounds3D(double x, double y, double z);
+	bool SavVarObs(GraphObj **gol, long ngo, DWORD flags);
+	DataObj *CreaCumData(char *xr, char *yr, int mode, double base);
+};
+
+class PlotScatt:public Plot{
+public:
+	char *xRange, *yRange;
+	long nPoints;
+	int DefSym;
+	lfPOINT BarDist;
+	Bar **Bars;
+	Symbol **Symbols;
+	DataLine *TheLine;
+	ErrorBar **Errors;
+	Label **Labels;
+
+	PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
+	PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars);
+	PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin);
+	PlotScatt(int src);
+	~PlotScatt();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *target);
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+	virtual bool PropertyDlg();
+	void RegGO(void *n);
+	virtual bool FileIO(int rw);
+
+	bool ForEach(int cmd, void *tmp, anyOutput *o);
+
+private:
+	DWORD DefSel;
+	char *ErrRange, *LbRange;
+	Arrow **Arrows;
+	DropLine **DropLines;
+
+	bool CreateBarChart();
+};
+
+class xyStat:public PlotScatt{
+public:
+	xyStat(GraphObj *par, DataObj *d);
+	xyStat(int src);
+	~xyStat();
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	virtual bool FileIO(int rw);
+
+	void CreateData();
+
+private:
+	double ci;
+	DataObj *curr_data;
+	char *case_prefix;
+
+};
+
+class BarChart:public PlotScatt{
+public:
+	BarChart(GraphObj *par, DataObj *d);
+};
+
+class FreqDist:public Plot {
+public:
+	FreqDist(GraphObj *par, DataObj *d);
+	FreqDist(int src);
+	~FreqDist();
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	double start, step;
+	long nPlots;
+	char *ssRef;
+	LineDEF BarLine, HatchLine;
+	FillDEF BarFill;
+	DataObj *curr_data;
+	GraphObj **plots;
+
+	void ProcData(int sel);
+};
+
+class Regression:public Plot{
+public:
+	Regression(GraphObj *par, DataObj *d);
+	Regression(int src);
+	~Regression();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *target);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	long nPoints;
+	char *xRange, *yRange;
+	Symbol **Symbols;
+	RegLine *rLine;
+	SDellipse *sde;
+
+	void Recalc();
+};
+
+class BubblePlot:public Plot{
+public:
+	BubblePlot(GraphObj *par, DataObj *d);
+	BubblePlot(int src);
+	~BubblePlot();
+	void DoPlot(anyOutput *target);
+	DWORD GetColor(int select);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	long nPoints;
+	LineDEF BubbleLine, BubbleFillLine;
+	FillDEF BubbleFill;
+	Bubble **Bubbles;
+};
+
+class PolarPlot:public Plot{
+public:
+	PolarPlot(GraphObj *par, DataObj *d);
+	PolarPlot(int src);
+	~PolarPlot();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+	bool AddPlot();
+	bool Config();
+
+private:
+	int nPlots, nAxes;
+	double offs;
+	anyOutput *CurrDisp;
+	fRECT CurrRect;
+	LineDEF FillLine;
+	FillDEF Fill;
+	Plot **Plots;
+	GraphObj **Axes;			//Axis not yet defined
+};
+
+class BoxPlot:public Plot {
+public:
+	BoxPlot(GraphObj *par, DataObj *d);
+	BoxPlot(int src);
+	BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3, char *box_name);
+	~BoxPlot();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+	bool ForEach(int cmd, void *tmp, anyOutput *o);
+	void CreateData();
+
+private:
+	char *xRange, *yRange, *case_prefix;
+	long nPoints;
+	double ci_box, ci_err;
+	DataObj *curr_data;
+	lfPOINT BoxDist;
+	Box **Boxes;
+	Whisker **Whiskers;
+	Symbol **Symbols;
+	Label **Labels;
+	DataLine *TheLine;
+};
+
+class DensDisp:public Plot {
+public:
+	DensDisp(GraphObj *par, DataObj *d);
+	DensDisp(int src);
+	~DensDisp();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	LineDEF DefLine, DefFillLine;
+	FillDEF DefFill;
+	long nPoints;
+	char *xRange, *yRange;
+	Box **Boxes;
+
+	void DoUpdate();
+
+};
+
+class StackBar:public Plot{
+public:
+	int numPlots, numXY, numPG, numPL;
+	BoxPlot **Boxes;
+	PlotScatt **xyPlots;
+	DataPolygon **Polygons;
+	DataLine **Lines;
+	lfPOINT dspm;
+
+	StackBar(GraphObj *par, DataObj *d);
+	StackBar(int src);
+	~StackBar();
+	bool SetSize(int select, double value);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	char *ssXrange, *ssYrange;
+	double StartVal;
+	int cum_data_mode;
+	DataObj *CumData;
+};
+
+class StackPG:public StackBar{
+public:
+	StackPG(GraphObj *par, DataObj *d);
+};
+
+class GroupBars:public StackBar{
+public:
+	GroupBars(GraphObj *par, DataObj *d):StackBar(par, d){};
+	bool PropertyDlg();
+};
+
+class Waterfall:public StackBar{
+public:
+	Waterfall(GraphObj *par, DataObj *d);
+	bool PropertyDlg();
 };
 
-class xyStat:public PlotScatt{
+class MultiLines:public StackBar{
 public:
-	xyStat(GraphObj *par, DataObj *d);
-	xyStat(int src);
-	~xyStat();
-	bool Command(int cmd, void *tmpl, anyOutput *o);
+	MultiLines(GraphObj *par, DataObj *d);
 	bool PropertyDlg();
-	virtual bool FileIO(int rw);
-
-	void CreateData();
-
-private:
-	double ci;
-	DataObj *curr_data;
-	char *case_prefix;
-
 };
-
-class BarChart:public PlotScatt{
-public:
-	BarChart(GraphObj *par, DataObj *d);
-};
 
-class FreqDist:public Plot {
+class PieChart:public Plot {
 public:
-	FreqDist(GraphObj *par, DataObj *d);
-	FreqDist(int src);
-	~FreqDist();
+	PieChart(GraphObj *par, DataObj *d);
+	PieChart(int src);
+	~PieChart();
+	bool SetSize(int select, double value);
 	void DoPlot(anyOutput *o);
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 	bool PropertyDlg();
 	void RegGO(void *n);
 	bool FileIO(int rw);
+	void DoUpdate();
 
 private:
-	double start, step;
-	long nPlots;
-	char *ssRef;
-	LineDEF BarLine, HatchLine;
-	FillDEF BarFill;
-	DataObj *curr_data;
-	GraphObj **plots;
+	long nPts;
+	char *ssRefA, *ssRefR;
+	lfPOINT CtDef;
+	double FacRad;
+	segment **Segments;
+};
 
-	void ProcData(int sel);
+class RingChart:public PieChart {
+public:
+	RingChart(GraphObj *par, DataObj *d);
 };
-
-class Regression:public Plot{
-public:
-	Regression(GraphObj *par, DataObj *d);
-	Regression(int src);
-	~Regression();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *target);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	long nPoints;
-	char *xRange, *yRange;
-	Symbol **Symbols;
-	RegLine *rLine;
-	SDellipse *sde;
-
-	void Recalc();
-};
-
-class BubblePlot:public Plot{
-public:
-	BubblePlot(GraphObj *par, DataObj *d);
-	BubblePlot(int src);
-	~BubblePlot();
-	void DoPlot(anyOutput *target);
-	DWORD GetColor(int select);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	long nPoints;
-	LineDEF BubbleLine, BubbleFillLine;
-	FillDEF BubbleFill;
-	Bubble **Bubbles;
-};
-
-class PolarPlot:public Plot{
-public:
-	PolarPlot(GraphObj *par, DataObj *d);
-	PolarPlot(int src);
-	~PolarPlot();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-
-	bool AddPlot();
-	bool Config();
-
-private:
-	int nPlots, nAxes;
-	double offs;
-	anyOutput *CurrDisp;
-	fRECT CurrRect;
-	LineDEF FillLine;
-	FillDEF Fill;
-	Plot **Plots;
-	GraphObj **Axes;			//Axis not yet defined
-};
-
-class BoxPlot:public Plot {
-public:
-	BoxPlot(GraphObj *par, DataObj *d);
-	BoxPlot(int src);
-	BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3);
-	~BoxPlot();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
 
-	bool ForEach(int cmd, void *tmp, anyOutput *o);
-	void CreateData();
-
-private:
-	char *xRange, *yRange, *case_prefix;
-	long nPoints;
-	double ci_box, ci_err;
-	DataObj *curr_data;
-	lfPOINT BoxDist;
-	Box **Boxes;
-	Whisker **Whiskers;
-	Symbol **Symbols;
-	Label **Labels;
-	DataLine *TheLine;
-};
-
-class DensDisp:public Plot {
-public:
-	DensDisp(GraphObj *par, DataObj *d);
-	DensDisp(int src);
-	~DensDisp();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	LineDEF DefLine, DefFillLine;
-	FillDEF DefFill;
-	long nPoints;
-	char *xRange, *yRange;
-	Box **Boxes;
-
-	void DoUpdate();
-
-};
-
-class StackBar:public Plot{
-public:
-	int numPlots, numXY, numPG, numPL;
-	BoxPlot **Boxes;
-	PlotScatt **xyPlots;
-	DataPolygon **Polygons;
-	DataLine **Lines;
-	lfPOINT dspm;
-
-	StackBar(GraphObj *par, DataObj *d);
-	StackBar(int src);
-	~StackBar();
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+class GoGroup:public Plot {
+public:
+	GraphObj **Objects;
+	int nObs;
+	lfPOINT fPos;
+
+	GoGroup(GraphObj *par, DataObj *d);
+	GoGroup(int src);
+	~GoGroup();
+	double GetSize(int select);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	char *ssXrange, *ssYrange;
-	double StartVal;
-	int cum_data_mode;
-	DataObj *CumData;
-};
-
-class StackPG:public StackBar{
-public:
-	StackPG(GraphObj *par, DataObj *d);
-};
-
-class GroupBars:public StackBar{
-public:
-	GroupBars(GraphObj *par, DataObj *d):StackBar(par, d){};
-	bool PropertyDlg();
-};
-
-class Waterfall:public StackBar{
-public:
-	Waterfall(GraphObj *par, DataObj *d);
-	bool PropertyDlg();
-};
+	bool FileIO(int rw);
+};
 
-class MultiLines:public StackBar{
+class StarChart:public GoGroup {
 public:
-	MultiLines(GraphObj *par, DataObj *d);
+	StarChart(GraphObj *par, DataObj *d);
 	bool PropertyDlg();
+
+private:
 };
-
-class PieChart:public Plot {
-public:
-	PieChart(GraphObj *par, DataObj *d);
-	PieChart(int src);
-	~PieChart();
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	void RegGO(void *n);
-	bool FileIO(int rw);
-	void DoUpdate();
-
-private:
-	long nPts;
-	char *ssRefA, *ssRefR;
-	lfPOINT CtDef;
-	double FacRad;
-	segment **Segments;
-};
-
-class RingChart:public PieChart {
-public:
-	RingChart(GraphObj *par, DataObj *d);
-};
-
-class GoGroup:public Plot {
-public:
-	GraphObj **Objects;
-	int nObs;
-	lfPOINT fPos;
-
-	GoGroup(GraphObj *par, DataObj *d);
-	GoGroup(int src);
-	~GoGroup();
-	double GetSize(int select);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	void RegGO(void *n);
-	bool FileIO(int rw);
-};
-
-class StarChart:public GoGroup {
-public:
-	StarChart(GraphObj *par, DataObj *d);
-	bool PropertyDlg();
-
-private:
-};
-
-class Ribbon:public Plot {
-public:
-	Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char *yr);
-	Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr);
+
+class Ribbon:public Plot {
+public:
+	Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char *yr);
+	Ribbon(GraphObj *par, DataObj *d, int which, char *xr, char *yr, char *zr);
 	Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo);
-	Ribbon(int src);
-	~Ribbon();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
+	Ribbon(int src);
+	~Ribbon();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	long nPlanes, nVal;
-	double z_value, z_width, relwidth;
-	char *ssRefX, *ssRefY, *ssRefZ;
-	FillDEF Fill;
+	bool FileIO(int rw);
+
+private:
+	long nPlanes, nVal;
+	double z_value, z_width, relwidth;
+	char *ssRefX, *ssRefY, *ssRefZ;
+	FillDEF Fill;
 	LineDEF Line;
-	fPOINT3D *values;
-	Plane3D **planes;
-
-	void CreateObs();
-	void UpdateObs(bool bNewData);
-};
+	fPOINT3D *values;
+	Plane3D **planes;
+
+	void CreateObs();
+	void UpdateObs(bool bNewData);
+};
 
 class Grid3D:public Plot {
 public:
@@ -1927,258 +2051,258 @@ private:
 	Arrow3D **Arrows;
 	Ribbon *rib;
 };
-
-class Limits:public Plot {
-public:
-	Limits(int src);
-	~Limits();
-	double GetSize(int select);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool FileIO(int rw);
-};
-
-class Function:public Plot{
-public:
-	Function(GraphObj *par, DataObj *d);
-	Function(int src);
-	~Function();
-	bool SetSize(int select, double value);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+
+class Limits:public Plot {
+public:
+	Limits(int src);
+	~Limits();
+	double GetSize(int select);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool FileIO(int rw);
+};
+
+class Function:public Plot{
+public:
+	Function(GraphObj *par, DataObj *d, char *desc);
+	Function(int src);
+	~Function();
+	bool SetSize(int select, double value);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
+	bool FileIO(int rw);
+
 	bool Update(anyOutput *o, DWORD flags);
-	LineDEF *GetLine() {return &Line;};
-
-private:
-	double x1,x2, xstep;
-	LineDEF Line;
-	char *param;
-	char *cmdxy;
-	DataLine *dl;
-};
-
-class FitFunc:public Plot{
-public:
-	FitFunc(GraphObj *par, DataObj *d);
-	FitFunc(int src);
-	~FitFunc();
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+	LineDEF *GetLine() {return &Line;};
+
+private:
+	double x1,x2, xstep;
+	LineDEF Line;
+	char *param;
+	char *cmdxy;
+	DataLine *dl;
+};
+
+class FitFunc:public Plot{
+public:
+	FitFunc(GraphObj *par, DataObj *d);
+	FitFunc(int src);
+	~FitFunc();
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	double x1, x2, xstep, conv, chi2;
-	char *ssXref, *ssYref;
-	long nPoints;
-	int maxiter;
-	LineDEF Line;
-	Symbol **Symbols;
-	char *cmdxy, *parxy;
-	Function *dl;
-};
-
-class GridLine:public GraphObj{
-public:
-	DWORD flags;
-	long ncpts;
-	POINT pts[6], *cpts;
-	LineDEF LineDef;
-	POINT3D *gl1, *gl2, *gl3;
-	line_segment **ls;
+	bool FileIO(int rw);
+
+private:
+	double x1, x2, xstep, conv, chi2;
+	char *ssXref, *ssYref;
+	long nPoints;
+	int maxiter;
+	LineDEF Line;
+	Symbol **Symbols;
+	char *cmdxy, *parxy;
+	Function *dl;
+};
+
+class GridLine:public GraphObj{
+public:
+	DWORD flags;
+	long ncpts;
+	POINT pts[6], *cpts;
+	LineDEF LineDef;
+	POINT3D *gl1, *gl2, *gl3;
+	line_segment **ls;
 	bool bModified;
 	anyOutput *mo;
-	RECT mrc;
-
-	GridLine(GraphObj *par, DataObj *d, int type, DWORD df);
-	GridLine(int src);
-	~GridLine();
-	virtual void DoPlot(anyOutput *o);
-	virtual void DoMark(anyOutput *o, bool mark);
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
-	bool FileIO(int rw);
-};
-
-class GridLine3D:public GridLine {
-public:
-	GridLine3D(GraphObj *par, DataObj *d, int type, DWORD df);
-	GridLine3D(int src);
-	~GridLine3D();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-};
-
-class GridRadial:public GridLine {
-public:
-	GridRadial(GraphObj *par, DataObj *d, int type, DWORD df);
-	GridRadial(int src);
-	~GridRadial();
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-};
-
-class Tick:public GraphObj{
-public:
-	Tick(GraphObj *par, DataObj *d, double val, DWORD Flags);
-	Tick(int src);
-	~Tick();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	bool SetColor(int select, DWORD col);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+	RECT mrc;
+
+	GridLine(GraphObj *par, DataObj *d, int type, DWORD df);
+	GridLine(int src);
+	~GridLine();
+	virtual void DoPlot(anyOutput *o);
+	virtual void DoMark(anyOutput *o, bool mark);
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+};
+
+class GridLine3D:public GridLine {
+public:
+	GridLine3D(GraphObj *par, DataObj *d, int type, DWORD df);
+	GridLine3D(int src);
+	~GridLine3D();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+};
+
+class GridRadial:public GridLine {
+public:
+	GridRadial(GraphObj *par, DataObj *d, int type, DWORD df);
+	GridRadial(int src);
+	~GridRadial();
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+};
+
+class Tick:public GraphObj{
+public:
+	Tick(GraphObj *par, DataObj *d, double val, DWORD Flags);
+	Tick(int src);
+	~Tick();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	bool SetColor(int select, DWORD col);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-	void DoPlot(double six, double csx, anyOutput *o);
-	
-private:
-	double value, size, fix, fiy, fiz, lsi, lcsi, angle, lbx, lby;
-	bool bModified;
+	bool FileIO(int rw);
+
+	void DoPlot(double six, double csx, anyOutput *o);
+	
+private:
+	double value, size, fix, fiy, fiz, lsi, lcsi, angle, lbx, lby;
+	bool bModified;
 	anyOutput *mo;
 	RECT mrc;
-	int gl_type;
-	GridLine *Grid;
-	Label *label;
-	DWORD flags;
-	POINT pts[2];
-	line_segment *ls;
-};
-
-class Axis:public GraphObj{
-public:
-	AxisDEF *axis;
-	LineDEF axline;
-
-	Axis(GraphObj *par, DataObj *d, AxisDEF *ax, DWORD flags);
-	Axis(int src);
-	~Axis();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+	int gl_type;
+	GridLine *Grid;
+	Label *label;
+	DWORD flags;
+	POINT pts[2];
+	line_segment *ls;
+};
+
+class Axis:public GraphObj{
+public:
+	AxisDEF *axis;
+	LineDEF axline;
+
+	Axis(GraphObj *par, DataObj *d, AxisDEF *ax, DWORD flags);
+	Axis(int src);
+	~Axis();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-	AxisDEF *GetAxis() {return axis;};
-	bool GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *o);
-	void TickFile(char *name);
-	void BreakSymbol(POINT3D *p1, double dsi, double dcsi, bool connect, anyOutput *o);
-	void DrawBreaks(anyOutput *o);
-
-private:
-	double sizAxLine, sizAxTick, sizAxTickLabel;
-	double si, csi;
-	double brksymsize, brkgap, tick_angle;
-	int brksym, nl_segs, gl_type, tick_type;
-	bool bModified;
-	DWORD colAxis;
-	LineDEF GridLine;
-	Tick **Ticks;
-	GraphObj *axisLabel;
-	long NumTicks;
-	POINT pts[2];
-	POINT3D pts3D[2];
-	fPOINT3D flim[2];
-	lfPOINT lbdist, tlbdist;
-	TextDEF tlbdef;
-	anyOutput *drawOut, *scaleOut;
-	line_segment **l_segs;
-	char *ssMATval, *ssMATlbl, *ssMITval; 
-	anyOutput *mo;
-	RECT mrc;
-
-	void SetTick(long idx, double val, DWORD flags, char *txt);
-	void CreateTicks();
-	void ManuTicks(double sa, double st, int n, DWORD flags);
-	void UpdateTicks();
-	bool ssTicks();
-
-};
-
-class Plot3D:public Plot{
-	typedef struct {
-		double Zmin, Zmax;
-		GraphObj *go;
-		}obj_desc;
-public:
-	long nPlots, nAxes;
-	Axis **Axes;
-	GraphObj **plots;
-	double *RotDef;
+	bool FileIO(int rw);
+
+	AxisDEF *GetAxis() {return axis;};
+	bool GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *o);
+	void TickFile(char *name);
+	void BreakSymbol(POINT3D *p1, double dsi, double dcsi, bool connect, anyOutput *o);
+	void DrawBreaks(anyOutput *o);
+
+private:
+	double sizAxLine, sizAxTick, sizAxTickLabel;
+	double si, csi;
+	double brksymsize, brkgap, tick_angle;
+	int brksym, nl_segs, gl_type, tick_type;
+	bool bModified;
+	DWORD colAxis;
+	LineDEF GridLine;
+	Tick **Ticks;
+	GraphObj *axisLabel;
+	long NumTicks;
+	POINT pts[2];
+	POINT3D pts3D[2];
+	fPOINT3D flim[2];
+	lfPOINT lbdist, tlbdist;
+	TextDEF tlbdef;
+	anyOutput *drawOut, *scaleOut;
+	line_segment **l_segs;
+	char *ssMATval, *ssMATlbl, *ssMITval; 
+	anyOutput *mo;
+	RECT mrc;
+
+	void SetTick(long idx, double val, DWORD flags, char *txt);
+	void CreateTicks();
+	void ManuTicks(double sa, double st, int n, DWORD flags);
+	void UpdateTicks();
+	bool ssTicks();
+
+};
+
+class Plot3D:public Plot{
+	typedef struct {
+		double Zmin, Zmax;
+		GraphObj *go;
+		}obj_desc;
+public:
+	long nPlots, nAxes;
+	Axis **Axes;
+	GraphObj **plots;
+	double *RotDef;
 	fPOINT3D cub1, cub2, rotC;
-
-	Plot3D(GraphObj *par, DataObj *d, DWORD flags);
-	Plot3D(int src);
-	~Plot3D();
-	double GetSize(int select);
-	bool SetColor(int select, DWORD col);
-	void DoPlot(anyOutput *o);
-	void DoMark(anyOutput *o, bool mark);
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
-	virtual bool PropertyDlg();
+
+	Plot3D(GraphObj *par, DataObj *d, DWORD flags);
+	Plot3D(int src);
+	~Plot3D();
+	double GetSize(int select);
+	bool SetColor(int select, DWORD col);
+	void DoPlot(anyOutput *o);
+	void DoMark(anyOutput *o, bool mark);
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+	virtual bool PropertyDlg();
 	virtual void RegGO(void *n);
-	virtual bool FileIO(int rw);
-
-	void * ObjThere(int x, int y);
-	void Track(POINT *p, anyOutput *o);
-	void CreateAxes();
-	void DoAutoscale();
-	void CalcRotation(double dx, double dy, anyOutput *o, bool accept);
-	bool AcceptObj(GraphObj *go);
-	void SortObj();
-	bool Rotate(double dx, double dy, double dz, anyOutput *o, bool accept);
-
-private:
-	long nObs, nmaxObs;
-	DWORD crea_flags;
-	Drag3D *drag;
-	fPOINT3D cu1, cu2, rc;
-	obj_desc **dispObs;
-
-	bool AddPlot(int family);
-};
-
-class Chart25D:public Plot3D {
-public:
-	Chart25D(GraphObj *par, DataObj *d, DWORD flags);
-	~Chart25D();
-	bool PropertyDlg();
-
-private:
-	fPOINT3D dspm;
-};
-
-class Ribbon25D:public Plot3D {
-public:
-	Ribbon25D(GraphObj *par, DataObj *d, DWORD flags);
-	~Ribbon25D();
-	bool PropertyDlg();
-
-private:
-	fPOINT3D dspm;
-};
-
-class BubblePlot3D:public Plot3D {
-public:
-	BubblePlot3D(GraphObj *par, DataObj *d);
-	~BubblePlot3D();
-	bool PropertyDlg();
-};
+	virtual bool FileIO(int rw);
+
+	void * ObjThere(int x, int y);
+	void Track(POINT *p, anyOutput *o);
+	void CreateAxes();
+	void DoAutoscale();
+	void CalcRotation(double dx, double dy, anyOutput *o, bool accept);
+	bool AcceptObj(GraphObj *go);
+	void SortObj();
+	bool Rotate(double dx, double dy, double dz, anyOutput *o, bool accept);
+
+private:
+	long nObs, nmaxObs;
+	DWORD crea_flags;
+	Drag3D *drag;
+	fPOINT3D cu1, cu2, rc;
+	obj_desc **dispObs;
+
+	bool AddPlot(int family);
+};
+
+class Chart25D:public Plot3D {
+public:
+	Chart25D(GraphObj *par, DataObj *d, DWORD flags);
+	~Chart25D();
+	bool PropertyDlg();
+
+private:
+	fPOINT3D dspm;
+};
+
+class Ribbon25D:public Plot3D {
+public:
+	Ribbon25D(GraphObj *par, DataObj *d, DWORD flags);
+	~Ribbon25D();
+	bool PropertyDlg();
+
+private:
+	fPOINT3D dspm;
+};
+
+class BubblePlot3D:public Plot3D {
+public:
+	BubblePlot3D(GraphObj *par, DataObj *d);
+	~BubblePlot3D();
+	bool PropertyDlg();
+};
 
 class Func3D:public Plot3D {
 public:
@@ -2223,72 +2347,76 @@ private:
 	DataObj *gda;
 	Grid3D  *gob;
 };
-
-class Graph:public GraphObj{
-public:
-	long NumPlots;
-	int ToolMode, units, nscp;
-	anyOutput *Disp, *CurrDisp;
-	fRECT GRect, DRect, Bounds;
-	bool OwnDisp, bModified;
-	fRECT CurrRect;
-	GraphObj **Plots, *PasteObj;
-	DWORD ColBG, ColAX;
-	GraphObj **Sc_Plots;
-	Axis **Axes;
-	char *filename;
-
-	Graph(GraphObj *par, DataObj *d, anyOutput *o);
-	Graph(int src);
-	~Graph();
-	double GetSize(int select);
-	bool SetSize(int select, double value);
-	DWORD GetColor(int select);
-	virtual void DoPlot(anyOutput *o);
-	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool PropertyDlg();
+
+class Graph:public GraphObj{
+public:
+	long NumPlots;
+	int ToolMode, units, nscp;
+	anyOutput *Disp, *CurrDisp;
+	fRECT GRect, DRect, Bounds;
+	bool OwnDisp, bModified;
+	fRECT CurrRect;
+	GraphObj **Plots, *PasteObj;
+	DWORD ColBG, ColAX;
+	GraphObj **Sc_Plots;
+	Axis **Axes;
+	char *filename;
+
+	Graph(GraphObj *par, DataObj *d, anyOutput *o);
+	Graph(int src);
+	~Graph();
+	double GetSize(int select);
+	bool SetSize(int select, double value);
+	DWORD GetColor(int select);
+	virtual void DoPlot(anyOutput *o);
+	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
-	virtual bool FileIO(int rw);
-
-private:
-	int NumAxes, AxisTempl, tickstyle, zoom_level;
-	RECT rcDim, rcUpd, rc_mrk;
-	DWORD ColDR, ColGR, ColGRL;
-	AxisDEF x_axis, y_axis;
-	FrmRect *frm_g, *frm_d;
-	bool dirty;
-	POINT *tl_pts;
-	long tl_nPts;
-	ZoomDEF *zoom_def;
-
-	bool AddPlot(int family);
-	void DoAutoscale();
-	void CreateAxes(int templ);
-	bool ExecTool(MouseEvent *mev);
-	bool Configure();
-	bool AddAxis();
-	bool MoveObj(int cmd, GraphObj *g); 
-	bool DoZoom(char *z);
-};
-
-class Page:public Graph{
-public:
-	Page(GraphObj *par, DataObj *d);
-	Page(int src);
-	void DoPlot(anyOutput *o);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
+	virtual bool FileIO(int rw);
+	virtual double DefSize(int select);
+
+private:
+	int NumAxes, AxisTempl, tickstyle, zoom_level;
+	double scale;
+	RECT rcDim, rcUpd, rc_mrk;
+	DWORD ColDR, ColGR, ColGRL;
+	AxisDEF x_axis, y_axis;
+	FrmRect *frm_g, *frm_d;
+	bool dirty;
+	POINT *tl_pts;
+	long tl_nPts;
+	ZoomDEF *zoom_def;
+
+	bool AddPlot(int family);
+	void DoAutoscale();
+	void CreateAxes(int templ);
+	bool ExecTool(MouseEvent *mev);
+	bool Configure();
+	bool AddAxis();
+	bool MoveObj(int cmd, GraphObj *g); 
+	bool DoZoom(char *z);
+	bool DoScale(scaleINFO *sc, anyOutput *o);
+};
+
+class Page:public Graph{
+public:
+	Page(GraphObj *par, DataObj *d);
+	Page(int src);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
 	void RegGO(void *n);
-	bool FileIO(int rw);
-
-private:
-	LineDEF LineDef;
-	FillDEF FillDef;
-
-	bool Configure();
-};
+	bool FileIO(int rw);
+	double DefSize(int select);
+
+private:
+	LineDEF LineDef;
+	FillDEF FillDef;
+
+	bool Configure();
+};
 
 class ObjTree:public GraphObj {
-public:
+public:
 	ObjTree(GraphObj *par, DataObj *d, GraphObj *root);
 	~ObjTree();
 	void DoPlot(anyOutput *o);
@@ -2307,342 +2435,360 @@ private:
 	TextDEF TextDef;
 };
 
-class notary{
-public:
-	notary();
-	~notary();
-	unsigned long RegisterGO(GraphObj *go);
-	void AddRegGO(GraphObj *go);
-	bool PushGO(unsigned long id, GraphObj *go);
-	GraphObj *PopGO(unsigned long id);
-	void FreeStack();
-
-private:
-	unsigned long NextPopGO, NextPushGO, NextRegGO;
-	GraphObj ***gObs;
-	GraphObj ***goStack;
-};
-
-class Default{
-public:
-	int dUnits, cUnits;
-	char DecPoint[2], ColSep[2];
-	char *svgAttr, *svgScript, *currPath, *IniFile;
+class notary{
+public:
+	notary();
+	~notary();
+	int RegisterGO(GraphObj *go);
+	void AddRegGO(GraphObj *go);
+	bool PushGO(unsigned int id, GraphObj *go);
+	GraphObj *PopGO(unsigned int id);
+	void FreeStack();
+
+private:
+	unsigned int NextPopGO, NextPushGO, NextRegGO;
+	GraphObj ***gObs;
+	GraphObj ***goStack;
+};
+
+class Default{
+public:
+	int dUnits, cUnits;
+	char DecPoint[2], ColSep[2];
+	char *svgAttr, *svgScript, *currPath, *IniFile;
 	char *File1, *File2, *File3, *File4, *File5, *File6;
-	char *fmt_date, *fmt_time, *fmt_datetime;
-	double min4log, ss_txt;
-	RECT clipRC;
-
-	Default();
-	~Default();
-	void SetDisp(anyOutput *o);
-	double GetSize(int select);
-	DWORD Color(int select);
-	LineDEF *GetLine();
-	void SetLine(int u, LineDEF *l, int which);
-	FillDEF *GetFill();
-	void SetFill(int u, FillDEF *fd);
-	LineDEF *GetOutLine();
-	bool PropertyDlg();
-	LineDEF *plLineDEF(LineDEF *ld);
-	LineDEF *pgLineDEF(LineDEF *ol);
-	FillDEF *pgFillDEF(FillDEF *fd);
-	double rrectRad(double rad);
-	void FileHistory(char *path);
-
-private:
-	LineDEF Line_0, Line_1, Line_2, *pl, *pgl;
-	FillDEF Fill_0, Fill_1, Fill_2, *pg;
-	LineDEF FillLine_0, FillLine_1, FillLine_2, *pg_fl;
-	LineDEF OutLine_0, OutLine_1, OutLine_2;
-	double *rrect_rad;
-	anyOutput *cdisp;
-	DWORD axis_color;
-};
-
-class DefsRW:public GraphObj{
-public:
-	DefsRW():GraphObj(0, 0){Id = 0; return;};
-	DefsRW(int rw):GraphObj(0,0){FileIO(rw);Id=GO_DEFRW;return;};
-	~DefsRW() {return;};
-	bool FileIO(int rw);
-};
-
-class ReadCache{
-public:
-	unsigned char last, *Cache, Line[4096];
-	int iFile, idx, max;
-	bool eof;
-
-	ReadCache();
-	~ReadCache();
-	virtual bool Open(char *name);
-	virtual void Close();
-	virtual unsigned char Getc();
-	virtual unsigned char *GetField();
-	void ReadLine(char *dest, int size);
-	bool GetInt(long *in);
-	bool GetFloat(double *fn);
-	unsigned char Lastc();
-	bool IsEOF();
-};
-
-class MemCache:public ReadCache{
-public:
-	MemCache(unsigned char *ptr);
-	~MemCache();
-	bool Open(char *name){return false;};
-	void Close(){return;};
-	unsigned char Getc();
-	unsigned char *GetField();
-};
-
-#define UNDO_CONTINUE 0x01
-#define UNDO_STORESET 0x1000
-class UndoObj {
-	enum {UNDO_UNDEFINED, UNDO_DEL_GO, UNDO_GOLIST, UNDO_DROPMEM,
-		UNDO_VALDWORD, UNDO_VALINT, UNDO_VALLONG, UNDO_OBJCONF, UNDO_OBJCONF_1,
+	char *fmt_date, *fmt_time, *fmt_datetime;
+	double min4log, ss_txt;
+	RECT clipRC;
+
+	Default();
+	~Default();
+	void SetDisp(anyOutput *o);
+	double GetSize(int select);
+	DWORD Color(int select);
+	LineDEF *GetLine();
+	void SetLine(int u, LineDEF *l, int which);
+	FillDEF *GetFill();
+	void SetFill(int u, FillDEF *fd);
+	LineDEF *GetOutLine();
+	bool PropertyDlg();
+	LineDEF *plLineDEF(LineDEF *ld);
+	LineDEF *pgLineDEF(LineDEF *ol);
+	FillDEF *pgFillDEF(FillDEF *fd);
+	double rrectRad(double rad);
+	void FileHistory(char *path);
+
+private:
+	LineDEF Line_0, Line_1, Line_2, *pl, *pgl;
+	FillDEF Fill_0, Fill_1, Fill_2, *pg;
+	LineDEF FillLine_0, FillLine_1, FillLine_2, *pg_fl;
+	LineDEF OutLine_0, OutLine_1, OutLine_2;
+	double *rrect_rad;
+	anyOutput *cdisp;
+	DWORD axis_color;
+};
+
+class DefsRW:public GraphObj{
+public:
+	DefsRW():GraphObj(0, 0){Id = 0; return;};
+	DefsRW(int rw):GraphObj(0,0){FileIO(rw);Id=GO_DEFRW;return;};
+	~DefsRW() {return;};
+	bool FileIO(int rw);
+};
+
+class ReadCache{
+public:
+	unsigned char last, *Cache, Line[4096];
+	int iFile, idx, max;
+	bool eof;
+
+	ReadCache();
+	~ReadCache();
+	virtual bool Open(char *name);
+	virtual void Close();
+	virtual unsigned char Getc();
+	virtual unsigned char *GetField();
+	void ReadLine(char *dest, int size);
+	bool GetInt(long *in);
+	bool GetFloat(double *fn);
+	unsigned char Lastc();
+	bool IsEOF();
+};
+
+class MemCache:public ReadCache{
+public:
+	MemCache(unsigned char *ptr);
+	~MemCache();
+	bool Open(char *name){return false;};
+	void Close(){return;};
+	unsigned char Getc();
+	unsigned char *GetField();
+};
+
+#define UNDO_CONTINUE 0x01
+#define UNDO_STORESET 0x1000
+class UndoObj {
+	enum {UNDO_UNDEFINED, UNDO_DEL_GO, UNDO_GOLIST, UNDO_DROPMEM,
+		UNDO_VALDWORD, UNDO_VALINT, UNDO_VALLONG, UNDO_OBJCONF, UNDO_OBJCONF_1,
 		UNDO_LFP, UNDO_POINT, UNDO_VOIDPTR, UNDO_MOVE, UNDO_RECT,
 		UNDO_STRING, UNDO_ROTDEF, UNDO_SETGO, UNDO_LINEDEF, UNDO_FILLDEF,
 		UNDO_AXISDEF, UNDO_LFP3D, UNDO_FLOAT, UNDO_MEM, UNDO_MUTATE, 
-		UNDO_DROPGOLIST, UNDO_TEXTDEF, UNDO_SAVVAR, UNDO_DATA, UNDO_ET};
-	typedef struct _UndoInfo {
-		int cmd;
-		DWORD flags;
-		GraphObj *owner;
-		void *data;
-		void **loc;
-		ZoomDEF zd;
-		}UndoInfo;
-
-	typedef struct _UndoList {
-		void *array;
-		void **loc_arr;
-		long count, size;
-		long *loc_count;
-		}UndoList;
-
-	typedef struct _UndoBuff {
-		int count;
-		UndoInfo **buff;
-		anyOutput *disp;
-		}UndoBuff;
+		UNDO_DROPGOLIST, UNDO_TEXTDEF, UNDO_SAVVAR, UNDO_DATA, UNDO_ET, UNDO_TEXTBUF};
+	typedef struct _UndoInfo {
+		int cmd;
+		DWORD flags;
+		GraphObj *owner;
+		void *data;
+		void **loc;
+		ZoomDEF zd;
+		}UndoInfo;
+
+	typedef struct _UndoList {
+		void *array;
+		void **loc_arr;
+		long count, size;
+		long *loc_count;
+		}UndoList;
+
+	typedef struct _UndoBuff {
+		int count;
+		UndoInfo **buff;
+		anyOutput *disp;
+		}UndoBuff;
 
 	typedef struct _EtBuff {
 		char *txt;
 		DataObj *DaO;
 		int *cur, *m1, *m2, vcur, vm1, vm2, row, col;
-		}EtBuff;
-
-public:
-	int *pcb;
+		}EtBuff;
+
+	typedef struct _TextBuff {
+		int *psize, size, *ppos, pos;
+		unsigned char **pbuff, *buff;
+		}TextBuff;
+
+public:
+	int *pcb;
 	anyOutput *cdisp, *ldisp;
 	bool busy;
-
+
 	UndoObj();
-	~UndoObj();
-	void Flush();
+	~UndoObj();
+	void Flush();
+	bool isEmpty(anyOutput *o);
 	void SetDisp(anyOutput *o);
-	void KillDisp(anyOutput *o);
-	void InvalidGO(GraphObj *go);
-	void Pop(anyOutput *o);
-	void Restore(bool redraw, anyOutput *o);
-	void ListGOmoved(GraphObj **oldlist, GraphObj **newlist, long size);
-	void DeleteGO(GraphObj **go, DWORD flags, anyOutput *o);
-	void MutateGO(GraphObj **old, GraphObj *repl, DWORD flags, anyOutput *o);
-	void StoreListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
-	void DropListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
-	void DropMemory(GraphObj *parent, void **mem, DWORD flags);
-	void SavVarBlock(GraphObj *parent, void **mem, DWORD flags);
+	void KillDisp(anyOutput *o);
+	void InvalidGO(GraphObj *go);
+	void Pop(anyOutput *o);
+	void Restore(bool redraw, anyOutput *o);
+	void ListGOmoved(GraphObj **oldlist, GraphObj **newlist, long size);
+	void DeleteGO(GraphObj **go, DWORD flags, anyOutput *o);
+	void MutateGO(GraphObj **old, GraphObj *repl, DWORD flags, anyOutput *o);
+	void StoreListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
+	void DropListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
+	void DropMemory(GraphObj *parent, void **mem, DWORD flags);
+	void SavVarBlock(GraphObj *parent, void **mem, DWORD flags);
 	void ValDword(GraphObj *parent, DWORD *val, DWORD flags);
-	void Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags);
+	void Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags);
 	void VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput * o, DWORD flags);
-	void ValInt(GraphObj *parent, int *val, DWORD flags);
+	void ValInt(GraphObj *parent, int *val, DWORD flags);
 	void ValLong(GraphObj *parent, long *val, DWORD flags);
-	void ObjConf(GraphObj *go, DWORD flags);
-	int SaveLFP(GraphObj *go, lfPOINT *lfp, DWORD flags);
-	void MoveObj(GraphObj *go, lfPOINT *lfp, DWORD flags);
-	void ValRect(GraphObj *go, fRECT *rec, DWORD flags);
-	void String(GraphObj *go, char **s, DWORD flags);
-	void RotDef(GraphObj *go, double **d, DWORD flags);
-	void SetGO(GraphObj *parent, GraphObj **where, GraphObj *go, DWORD flags);
-	void Line(GraphObj *go, LineDEF *ld, DWORD flags);
-	void Fill(GraphObj *go, FillDEF *fd, DWORD flags);
-	void AxisDef(GraphObj *go, AxisDEF *ad, DWORD flags);
-	void TextDef(GraphObj *go, TextDEF *td, DWORD flags);
-	void ValLFP3D(GraphObj *go, fPOINT3D *lfp, DWORD flags);
-	void ValFloat(GraphObj *parent, double *val, DWORD flags);
+	void ObjConf(GraphObj *go, DWORD flags);
+	int SaveLFP(GraphObj *go, lfPOINT *lfp, DWORD flags);
+	void MoveObj(GraphObj *go, lfPOINT *lfp, DWORD flags);
+	void ValRect(GraphObj *go, fRECT *rec, DWORD flags);
+	int String(GraphObj *go, char **s, DWORD flags);
+	void RotDef(GraphObj *go, double **d, DWORD flags);
+	void SetGO(GraphObj *parent, GraphObj **where, GraphObj *go, DWORD flags);
+	void Line(GraphObj *go, LineDEF *ld, DWORD flags);
+	void Fill(GraphObj *go, FillDEF *fd, DWORD flags);
+	void AxisDef(GraphObj *go, AxisDEF *ad, DWORD flags);
+	void TextDef(GraphObj *go, TextDEF *td, DWORD flags);
+	void ValLFP3D(GraphObj *go, fPOINT3D *lfp, DWORD flags);
+	void ValFloat(GraphObj *parent, double *val, DWORD flags);
 	void DataMem(GraphObj *go, void **mem, int size, long *count, DWORD flags);
 	void DataObject(GraphObj *go, anyOutput *o, DataObj *d, RECT *rc, DWORD flags);
 	void TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int *m2, void* DaO, DWORD flags);
-
-private:
-	UndoInfo **buff, **buff0;
-	int stub1, ndisp;
-	UndoBuff **buffers;
-
-	int NewItem(int cmd, DWORD flags, GraphObj *owner, void *data, void **loc);
-	void FreeInfo(UndoInfo** inf);
+	void TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o); 
+
+private:
+	UndoInfo **buff, **buff0;
+	int stub1, ndisp;
+	UndoBuff **buffers;
+
+	int NewItem(int cmd, DWORD flags, GraphObj *owner, void *data, void **loc);
+	void FreeInfo(UndoInfo** inf);
 	void RestoreConf(UndoInfo *inf);
-	void RestoreData(UndoInfo *inf);
-};
-
-//prototypes: spreadwi.cpp
-int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch);
-void SpreadMain(bool show);
-
-//prototypes: WinSpec.cpp or QT_Spec.cpp
-char *SaveDataAsName(char *oldname);
-char *SaveGraphAsName(char *oldname);
-char *OpenGraphName(char *oldname);
-char *OpenDataName(char *oldname);
-void InfoBox(char *Msg);
-void ErrorBox(char *Msg);
-bool YesNoBox(char *Msg);
+	void RestoreData(UndoInfo *inf);
+};
+
+//prototypes: spreadwi.cpp
+int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch);
+void SpreadMain(bool show);
+
+//prototypes: WinSpec.cpp or QT_Spec.cpp
+char *SaveDataAsName(char *oldname);
+char *SaveGraphAsName(char *oldname);
+char *OpenGraphName(char *oldname);
+char *OpenDataName(char *oldname);
+void InfoBox(char *Msg);
+void ErrorBox(char *Msg);
+bool YesNoBox(char *Msg);
 int YesNoCancelBox(char *Msg);
-void Qt_Box();
-void HideTextCursor();
-void HideTextCursorObj(anyOutput *out);
-void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color);
-void HideCopyMark();
-void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec);
-void InitTextCursor(bool init);
-void EmptyClip();
+void Qt_Box();
+void HideTextCursor();
+void HideTextCursorObj(anyOutput *out);
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color);
+void HideCopyMark();
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec);
+void InitTextCursor(bool init);
+void EmptyClip();
 void CopyText(char *txt, int len);
 unsigned char* PasteText();
-void GetDesktopSize(int *width, int *height);
-void FindBrowser();
-void LoopDlgWnd();
-void CloseDlgWnd(void *hDlg);
-void ShowDlgWnd(void *hDlg);
-anyOutput *NewDispClass(GraphObj *g);
-bool DelDispClass(anyOutput *w);
-anyOutput *NewBitmapClass(int w, int h, double hr, double vr);
-bool DelBitmapClass(anyOutput *w);
-
-//prototypes: FileIO.cpp
-bool SaveGraphAs(GraphObj *g);
-char *GraphToMem(GraphObj *g, long *size);
-void UpdGOfromMem(GraphObj *go, unsigned char *buff);
-bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste);
-void SavVarInit(long len);
-void *SavVarFetch();
-
-//prototypes:TheDialog.cpp
-DWORD GetNewColor(DWORD oldcol);
+void GetDesktopSize(int *width, int *height);
+void FindBrowser();
+void LoopDlgWnd();
+void CloseDlgWnd(void *hDlg);
+void ShowDlgWnd(void *hDlg);
+void ResizeDlgWnd(void *hDlg, int w, int h);
+anyOutput *NewDispClass(GraphObj *g);
+bool DelDispClass(anyOutput *w);
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr);
+bool DelBitmapClass(anyOutput *w);
+
+//prototypes: FileIO.cpp
+bool SaveGraphAs(GraphObj *g);
+char *GraphToMem(GraphObj *g, long *size);
+void UpdGOfromMem(GraphObj *go, unsigned char *buff);
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste);
+void SavVarInit(long len);
+void *SavVarFetch();
+
+//prototypes:TheDialog.cpp
+DWORD GetNewColor(DWORD oldcol);
 bool ShowLayers(GraphObj *root);
-void GetNewFill(FillDEF *oldfill);
-void ShowBanner(bool show);
-void RLPlotInfo();
-bool DoSpShSize(DataObj *dt);
-bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go);
-bool GetBitmapRes(double *res, double *width, double *height, char *header);
-void OD_scheme(int, void *, RECT *, anyOutput *, void *, int);
-FillDEF *GetSchemeFill(int *i);
-void OD_linedef(int, void *, RECT *, anyOutput *o, void *, int);
-void OD_filldef(int, void *, RECT *, anyOutput *o, void *, int);
-void OD_paperdef(int, void *, RECT *, anyOutput *o, void *, int);
-void FindPaper(double w, double h, double tol);
-bool GetPaper(double *w, double *h);
-void OD_axisplot(int, void *, RECT *, anyOutput *o, void *, int);
-
-//prototypes: Utils.cpp
-anyOutput *GetRectBitmap(RECT *rc, anyOutput *src);
-void RestoreRectBitmap(anyOutput **pmo, RECT *mrc, anyOutput *o);
-void NiceAxis(AxisDEF *axis, int nTick);
-void NiceStep(AxisDEF *axis, int nTick);
-double base4log(AxisDEF *axis, int direc);
-double TransformValue(AxisDEF *axis, double val, bool transform);
-void SortAxisBreaks(AxisDEF *axis);
-double GetAxisFac(AxisDEF *axis, double delta, int direc);
+void GetNewFill(FillDEF *oldfill);
+void ShowBanner(bool show);
+void RLPlotInfo();
+bool DoSpShSize(DataObj *dt);
+bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go);
+bool GetBitmapRes(double *res, double *width, double *height, char *header);
+void OD_scheme(int, void *, RECT *, anyOutput *, void *, int);
+FillDEF *GetSchemeFill(int *i);
+void OD_linedef(int, void *, RECT *, anyOutput *o, void *, int);
+void OD_filldef(int, void *, RECT *, anyOutput *o, void *, int);
+void OD_paperdef(int, void *, RECT *, anyOutput *o, void *, int);
+void FindPaper(double w, double h, double tol);
+bool GetPaper(double *w, double *h);
+void OD_axisplot(int, void *, RECT *, anyOutput *o, void *, int);
+
+//prototypes: Utils.cpp
+anyOutput *GetRectBitmap(RECT *rc, anyOutput *src);
+void RestoreRectBitmap(anyOutput **pmo, RECT *mrc, anyOutput *o);
+void NiceAxis(AxisDEF *axis, int nTick);
+void NiceStep(AxisDEF *axis, int nTick);
+double base4log(AxisDEF *axis, int direc);
+double TransformValue(AxisDEF *axis, double val, bool transform);
+void SortAxisBreaks(AxisDEF *axis);
+double GetAxisFac(AxisDEF *axis, double delta, int direc);
 char *str_ltrim(char *str);
 char *str_rtrim(char *str);
 char *str_trim(char *str);
+void rmquot(char *str);
+int strpos(char *needle, char *haystack);
+char *strreplace(char *needle, char *replace, char *haystack);
+char *substr(char *text, int pos1, int pos2);
+int rlp_strcpy(char*dest, int size, char*src);
 void ReshapeFormula(char **text);
 void TranslateResult(anyResult *res);
 void CleanTags(char *txt, int *i1, int *i2, int *i3);
-void ChangeChar(char *text, char c1, char c2);
-char *Int2Nat(char *Text);
-char *Nat2Int(char *Text);
-void WriteNatFloatToBuff(char *buff, double val);
-bool Txt2Flt(char *txt, double *val);
-void RmTrail(char *txt);
-double NiceValue(double fv);
-char *Int2ColLabel(int nr, bool uc);
-char *str2xml(char *str);
-char **split(char *str, char sep, int *nl);
+void ChangeChar(char *text, char c1, char c2);
+char *Int2Nat(char *Text);
+char *Nat2Int(char *Text);
+void WriteNatFloatToBuff(char *buff, double val);
+bool Txt2Flt(char *txt, double *val);
+void RmTrail(char *txt);
+double NiceValue(double fv);
+char *Int2ColLabel(int nr, bool uc);
+char *str2xml(char *str);
+char **split(char *str, char sep, int *nl);
 char *fit_num_rect(anyOutput *o, int max_width, char *num_str);
-void SetMinMaxRect(RECT *rc, int x1, int y1, int x2, int y2);
-void UpdateMinMaxRect(RECT *rc, int x, int y);
-void IncrementMinMaxRect(RECT *rc, int i);
-bool IsInRect(RECT *rc, int x, int y);
-bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y);
-bool IsCloseToPL(POINT p, POINT *pts, int cp);
-bool IsInPolygon(POINT *p, POINT *pts, int cp);
-bool OverlapRect(RECT *rc1, RECT *rc2);
+void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len);
+void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig);
+void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp);
+void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp);
+void SetMinMaxRect(RECT *rc, int x1, int y1, int x2, int y2);
+void UpdateMinMaxRect(RECT *rc, int x, int y);
+void IncrementMinMaxRect(RECT *rc, int i);
+bool IsInRect(RECT *rc, int x, int y);
+bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y);
+bool IsCloseToPL(POINT p, POINT *pts, int cp);
+bool IsInPolygon(POINT *p, POINT *pts, int cp);
+bool OverlapRect(RECT *rc1, RECT *rc2);
 void AddToPolygon(long *cp, POINT *pts, POINT *np);
-void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth=0);
-POINT *MakeArc(int ix, int iy, int r, int qad, long *npts);
-void InvertPolygon(POINT*, int, LineDEF*, FillDEF*, RECT*, anyOutput*, bool);
-void InvertLine(POINT*, int, LineDEF*, RECT*, anyOutput*, bool);
-unsigned int ColDiff(DWORD col1, DWORD col2);
-DWORD IpolCol(DWORD color1, DWORD color2, double fact);
-double ran2(long *idum);
-unsigned long isqr(unsigned long n);
-bool MatMul(double a[3][3], double b[3][3], double c[3][3]);
-char *GetNumFormat(double Magn);
-void DeleteGO(GraphObj *go);
+void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth=0);
+POINT *MakeArc(int ix, int iy, int r, int qad, long *npts);
+void InvertPolygon(POINT*, int, LineDEF*, FillDEF*, RECT*, anyOutput*, bool);
+void InvertLine(POINT*, int, LineDEF*, RECT*, anyOutput*, bool);
+unsigned int ColDiff(DWORD col1, DWORD col2);
+DWORD IpolCol(DWORD color1, DWORD color2, double fact);
+double ran2(long *idum);
+unsigned long isqr(unsigned long n);
+bool MatMul(double a[3][3], double b[3][3], double c[3][3]);
+char *GetNumFormat(double Magn);
+void DeleteGO(GraphObj *go);
 bool DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o);
-bool BackupFile(char *FileName);
-bool IsRlpFile(char *FileName);
+bool BackupFile(char *FileName);
+bool IsRlpFile(char *FileName);
 bool IsXmlFile(char *FileName);
-bool FileExist(char *FileName);
+bool FileExist(char *FileName);
 bool IsPlot3D(GraphObj *g);
-void *memdup(void *ptr, int cb_old, int cb_new);
-double sininv(double val);
-double trig2deg(double si, double csi);
-bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj);
-unsigned int HashValue(unsigned char *str);
+void *memdup(void *ptr, int cb_old, int cb_new);
+double sininv(double val);
+double trig2deg(double si, double csi);
+bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj);
+unsigned int HashValue(unsigned char *str);
 unsigned int Hash2(unsigned char * str);
-bool cmpLineDEF(LineDEF *l1, LineDEF *l2);
-bool cmpFillDEF(FillDEF *f1, FillDEF *f2);
-bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2);
-bool cmpTextDEF(TextDEF *t1, TextDEF *t2);
-DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWORD flags);
-DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags);
-DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags);
-DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags);
-void clip_line_sphere(GraphObj *par, POINT3D **li, int r, int cx, int cy, int cz);
-void clip_line_plane(GraphObj *par, POINT3D **li, POINT3D *pg, int np, double *vec);
-void clip_sphline_sphere(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent, 
-	int r1, int r2, int cx, int cy, int cz);
-void clip_sphline_plane(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent, 
-	int r1, POINT3D *pg, int np, double *vec);
-void clip_plane_plane(GraphObj *par, POINT3D *pg1, int n1, double *v1, POINT3D *pg2, 
-	int n2, double *v2, POINT *m, int nm);
-
-//prototypes Export.cpp
-void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags);
-void DoExportSvg(GraphObj *g, char *FileName, DWORD flags);
-void DoExportEps(GraphObj *g, char *FileName, DWORD flags);
-
-//prototypes Output.cpp
-void DoExportTif(GraphObj *g, char *FileName, DWORD flags);
-
-//prototypes mfcalc.cpp
-bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, char *);
+bool cmpLineDEF(LineDEF *l1, LineDEF *l2);
+bool cmpFillDEF(FillDEF *f1, FillDEF *f2);
+bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2);
+bool cmpTextDEF(TextDEF *t1, TextDEF *t2);
+DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags);
+void clip_line_sphere(GraphObj *par, POINT3D **li, int r, int cx, int cy, int cz);
+void clip_line_plane(GraphObj *par, POINT3D **li, POINT3D *pg, int np, double *vec);
+void clip_sphline_sphere(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent, 
+	int r1, int r2, int cx, int cy, int cz);
+void clip_sphline_plane(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent, 
+	int r1, POINT3D *pg, int np, double *vec);
+void clip_plane_plane(GraphObj *par, POINT3D *pg1, int n1, double *v1, POINT3D *pg2, 
+	int n2, double *v2, POINT *m, int nm);
+
+//prototypes Export.cpp
+void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags);
+void DoExportSvg(GraphObj *g, char *FileName, DWORD flags);
+void DoExportEps(GraphObj *g, char *FileName, DWORD flags);
+
+//prototypes Output.cpp
+void DoExportTif(GraphObj *g, char *FileName, DWORD flags);
+
+//prototypes mfcalc.cpp
+char  *yywarn(char *txt, bool bNew);
+bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, char *);
 bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, 
 	char *expr, char *param);
-anyResult *do_formula(DataObj *, char *);
-bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0);
+anyResult *do_formula(DataObj *, char *);
+bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0);
 int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, 
-	double conv, int maxiter, double *chi_2);
-
-//prototypes rlp_math.cp
-double **dmatrix(int nrl, int nrh, int ncl, int nch);
-void free_dmatrix(double **m, int nrl, int nrh, int ncl, int);
-bool mrqmin(double *, double *, double *, int, double **, int, int *, int, double **, double **, double *,
-	void (*funcs)(double, double, double **, double *, double *, int), double *);
+	double conv, int maxiter, double *chi_2);
+
+//prototypes rlp_math.cp
+double **dmatrix(int nrl, int nrh, int ncl, int nch);
+void free_dmatrix(double **m, int nrl, int nrh, int ncl, int);
+bool mrqmin(double *, double *, double *, int, double **, int, int *, int, double **, double **, double *,
+	void (*funcs)(double, double, double **, double *, double *, int), double *);
 bool Check_MRQerror();
 void SortArray(int n, double *vals);
 void SortFpArray(int n, lfPOINT *vals);
@@ -2665,9 +2811,12 @@ double exp_freq(double x, double l, double s);
 double lognorm_dist(double x, double m, double s);
 double lognorm_freq(double x, double m, double s);
 double chi_dist(double x, double df, double);
+double chi_freq(double x, double df);
 double t_dist(double t, double df, double);
+double t_freq(double t, double df);
 double pois_dist(double x, double m, double);
 double f_dist(double f, double df1, double df2);
+double f_freq(double f, double df1, double df2);
 double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0);
 void d_quartile(int n, double *v, double *q1, double *q2, double *q3);
 double d_variance(int n, double *v, double *mean = 0L, double *ss = 0L);
@@ -2684,16 +2833,20 @@ double d_spearman(double *x, double *y, int n, char *dest, DataObj *data);
 double d_kendall(double *x, double *y, int n, char *dest, DataObj *data);
 double d_regression(double *x, double *y, int n, char *dest, DataObj *data);
 double d_covar(double *x, double *y, int n, char *dest, DataObj *data);
-double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data);
-double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data);
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
+double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
 double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data);
 double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data);
 bool date_value(char *desc, char *fmt, double *value);
 char *value_date(double dv, char *fmt);
 double now_today();
 void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s);
+Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data);
 Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *text1, char *text2, char *text3);
 
 //prototypes reports.cpp
 void rep_anova(GraphObj *parent, DataObj *data);
 void rep_regression(GraphObj *parent, DataObj *data);
+void rep_twowaytable(GraphObj *parent, DataObj *data);
+void rep_compmeans(GraphObj *parent, DataObj *data);
+
diff --git a/rlplot.spec b/rlplot.spec
index e280847..88e95c3 100755
--- a/rlplot.spec
+++ b/rlplot.spec
@@ -1,5 +1,5 @@
 Name:      rlplot
-Version:   1.1
+Version:   1.2
 Release:   1
 Summary:   A plotting program to create high quality graphs from data.
 License:   GPL
@@ -41,6 +41,9 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_bindir}/exprlp
 
 %changelog
+* Thu Oct 19 2006 Reinhard Lackner
+- release 1.2
+
 * Fri Feb 24 2006 Reinhard Lackner
 - release 1.1
 
@@ -59,3 +62,4 @@ rm -rf "$RPM_BUILD_ROOT"
 * Mon Nov 25 2002 Guido Gonzato
 - initial
 
+
diff --git a/spreadwi.cpp b/spreadwi.cpp
index d8c0ed5..72a5740 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -1,200 +1,205 @@
-//spreadwin.cpp, (c)2000-2006 by R. Lackner
-//
-//    This file is part of RLPlot.
-//
-//    RLPlot 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.
-//
-//    RLPlot 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 RLPlot; if not, write to the Free Software
-//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-//
-#include "rlplot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+//spreadwin.cpp, (c)2000-2006 by R. Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot 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.
+//
+//    RLPlot 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 RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
-#include <math.h>
-
-#include <fcntl.h>				//file open flags
-#include <sys/stat.h>			//I/O flags
-
-#ifdef _WINDOWS
-	#include <io.h>					//for read/write
-#else
-	#define O_BINARY 0x0
-	#include <unistd.h>
-#endif
-
-extern const LineDEF GrayLine;
-extern EditText *CurrText;
-extern char *LoadFile;
-extern char TmpTxt[];
-extern Default defs;
-extern UndoObj Undo;
-
-static ReadCache *Cache = 0L;
+#include <math.h>
+
+#include <fcntl.h>				//file open flags
+#include <sys/stat.h>			//I/O flags
+
+#ifdef _WINDOWS
+	#include <io.h>					//for read/write
+#else
+	#define O_BINARY 0x0
+	#include <unistd.h>
+#endif
+
+extern const LineDEF GrayLine;
+extern GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
+extern EditText *CurrText;
+extern char *LoadFile;
+extern char TmpTxt[];
+extern Default defs;
+extern UndoObj Undo;
+
+static ReadCache *Cache = 0L;
 static TextDEF ssText;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get item from *.csv file
-bool GetItemCSV(char *Text, int cbText)
-{
-	char c;
-	int i;
-
-	for (i = 0,	*Text = 0; i < cbText; ) {
-		c = Cache->Getc();
-		switch(c) {
-		case ',':			//column separator
-			Text[i] = 0;
-			return true;
-		case 0x0a:			//end of line: mark by false return but text o.k.
-			Text[i] = 0;
-			return false;
-		default:
-			if(c > 0x20) Text[i++] = c;	//printable character
-			else if(i >0 && c == 0x20) Text[i++] = c;
-			else if(!c && Cache->IsEOF()) {
-				Text[i] = 0;
-				return false;
-				}
-			else Text[i] = 0;	//ignore non printing characters
-			}
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// process a memory block (i.e. clipboard data) as if file input
-int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch)
-{
-	int i, RetVal = FF_UNKNOWN, nt, nl, nc, ns;
-
-	if(ptr) {
-		for(i = nt = nl = nc = ns = 0; ptr[i] && nl<100; i++) {
-			switch(ptr[i]) {
-			case 0x09:				//tab
-				nt++;
-				break;
-			case 0x0a:				//LF
-				nl++;
-				break;
-			case ',':
-				nc++;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get item from *.csv file
+bool GetItemCSV(char *Text, int cbText)
+{
+	char c;
+	int i;
+
+	for (i = 0,	*Text = 0; i < cbText; ) {
+		c = Cache->Getc();
+		switch(c) {
+		case ',':			//column separator
+			Text[i] = 0;
+			return true;
+		case 0x0a:			//end of line: mark by false return but text o.k.
+			Text[i] = 0;
+			return false;
+		default:
+			if(c > 0x20) Text[i++] = c;	//printable character
+			else if(i >0 && c == 0x20) Text[i++] = c;
+			else if(!c && Cache->IsEOF()) {
+				Text[i] = 0;
+				return false;
+				}
+			else Text[i] = 0;	//ignore non printing characters
+			}
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// process a memory block (i.e. clipboard data) as if file input
+int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch)
+{
+	int i, RetVal = FF_UNKNOWN, nt, nl, nc, ns;
+
+	if(ptr) {
+		for(i = nt = nl = nc = ns = 0; ptr[i] && nl<100; i++) {
+			switch(ptr[i]) {
+			case 0x09:				//tab
+				nt++;
+				break;
+			case 0x0a:				//LF
+				nl++;
 				break;
-			case ' ':
+			case ',':
+				nc++;
+				break;
+			case ' ':
 				ns++;
 				break;
-				}
-			}
-		if(dispatch && i && !nt && !nl) {
+				}
+			}
+		if(dispatch && i && !nt && !nl) {
 			if(CurrText){
 				g->Command(CMD_SETFOCUS, 0L, 0L);
-				for(i = 0; ptr[i]; i++)	CurrText->AddChar(ptr[i], i? 0L : Undo.cdisp, 0L);
+				for(i = 0; ptr[i]; i++)	CurrText->AddChar(ptr[i], i? 0L : Undo.cdisp, 0L);
 				g->Command(CMD_REDRAW, 0L, 0L);
 				}
-			}
-		else if(nt) RetVal = FF_TSV;
-		else if(nl && ptr[0] == '<') RetVal = FF_XML;
-		else if(nc == nl && defs.DecPoint[0] == ',') RetVal = FF_TSV;
-		else if(nl && nc && 0 == (nc % nl)) RetVal = FF_CSV;
+			}
+		else if(nt) RetVal = FF_TSV;
+		else if(nl && ptr[0] == '<') RetVal = FF_XML;
+		else if(nc == nl && defs.DecPoint[0] == ',') RetVal = FF_TSV;
+		else if(nl && nc && 0 == (nc % nl)) RetVal = FF_CSV;
 		else if(nl && ns && 0 == (ns % nl)) RetVal = FF_SSV;
-		else if(nl) RetVal = FF_TSV;
-		if(dispatch) switch(RetVal) {
-		case FF_CSV:	g->Command(CMD_PASTE_CSV, ptr, 0L);	break;
-		case FF_TSV:	g->Command(CMD_PASTE_TSV, ptr, 0L);	break;
+		else if(nl) RetVal = FF_TSV;
+		if(dispatch) switch(RetVal) {
+		case FF_CSV:	g->Command(CMD_PASTE_CSV, ptr, 0L);	break;
+		case FF_TSV:	g->Command(CMD_PASTE_TSV, ptr, 0L);	break;
 		case FF_SSV:	g->Command(CMD_PASTE_SSV, ptr, 0L);	break;
-		case FF_XML:	g->Command(CMD_PASTE_XML, ptr, 0L); break;
-			}
-		}
-	return RetVal;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// This graphic object displays a spreadsheet
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class SpreadWin:public GraphObj{
-public:
-	anyOutput *w;
-	POINT ssOrg;
-	RECT currRC;
-
-	SpreadWin(GraphObj *par, DataObj *Data);
-	~SpreadWin();
-	void DoPlot(anyOutput *target);
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-
-	bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cpos);
+		case FF_XML:	g->Command(CMD_PASTE_XML, ptr, 0L); break;
+			}
+		}
+	return RetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This graphic object displays a spreadsheet
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SpreadWin:public GraphObj{
+public:
+	anyOutput *w;
+	POINT ssOrg;
+	RECT currRC;
+
+	SpreadWin(GraphObj *par, DataObj *Data);
+	~SpreadWin();
+	void DoPlot(anyOutput *target);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+
+	bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cpos);
 	void MarkButtons(char *rng, POINT *cp = 0L);
 	bool PrintData(anyOutput *o);
-	void WriteGraphXML(unsigned char **ptr, long *cbd);
-
-private:
-	int ch, cw, fw;				//cell height and width, row button width
-	bool is_modified;
-	char *filename;
+	void WriteGraphXML(unsigned char **ptr, long *cbd);
+
+private:
+	bool is_modified, bDoColWidth;
+	char *filename;
 	ssButton **cButtons, **rButtons;
 	ssButton *aButton;
-	POINT cpos;
-	DataObj *d;
-	int NumGraphs;
-	Graph **g;
-};
-
-SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
-{
-	d = Data;	g = 0L;		ssOrg.x =  ssOrg.y = 0;		NumGraphs = 0;
-	ch = 19;	cw = 76;	fw = 32;	filename=0L;	aButton = 0L;
-	w = 0L;		cButtons = rButtons = 0L;
-	if(w = NewDispClass(this)){
-		w->hasHistMenu = true;
-		ssText.RotBL = ssText.RotCHAR = 0.0;
-		ssText.fSize = 0.0f;
-#ifdef _WINDOWS
-		ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT));
-#else
-		ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT)*.7);
-#endif
-		ssText.Align = TXA_VCENTER | TXA_HLEFT;		ssText.Mode = TXM_TRANSPARENT;
-		ssText.Style = TXS_NORMAL;					ssText.ColBg = 0x00e8e8e8L;
-		ssText.ColTxt = 0x00000000L;				ssText.text = 0L;
-		ssText.Font = FONT_HELVETICA;				w->SetTextSpec(&ssText);
-		w->SetMenu(MENU_SPREAD);					w->FileHistory();
-		w->Erase(0x00e8e8e8L);						w->Caption("RLPlot data");
-		cw = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
-		ch = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
-		fw = 32;
-		}
-	cButtons = rButtons = 0L;
+	POINT cpos;
+	DataObj *d;
+	int NumGraphs, CurrCol;
+	Graph **g;
+	RECT rc_line;
+	POINT line[2];
+};
+
+SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
+{
+	d = Data;	g = 0L;		ssOrg.x =  ssOrg.y = 0;		NumGraphs = 0;
+	filename=0L;	aButton = 0L;
+	w = 0L;		cButtons = rButtons = 0L;
+	if(w = NewDispClass(this)){
+		w->hasHistMenu = true;
+		ssText.RotBL = ssText.RotCHAR = 0.0;
+		ssText.fSize = 0.0f;
+#ifdef _WINDOWS
+		ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT));
+#else
+		ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT)*.7);
+#endif
+		ssText.Align = TXA_VCENTER | TXA_HLEFT;		ssText.Mode = TXM_TRANSPARENT;
+		ssText.Style = TXS_NORMAL;					ssText.ColBg = 0x00e8e8e8L;
+		ssText.ColTxt = 0x00000000L;				ssText.text = 0L;
+		ssText.Font = FONT_HELVETICA;				w->SetTextSpec(&ssText);
+		w->SetMenu(MENU_SPREAD);					w->FileHistory();
+		w->Erase(0x00e8e8e8L);						w->Caption("RLPlot data");
+		d->ri->SetDefWidth(w->un2ix(defs.GetSize(SIZE_CELLWIDTH)));
+		d->ri->SetHeight(w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2);
+		d->ri->SetFirstWidth(32);
+		}
+	else if(d &&  d->ri) {
+		d->ri->SetHeight(19);	d->ri->SetDefWidth(76);	d->ri->SetFirstWidth(32);
+		}
+	cButtons = rButtons = 0L;
 	Id = GO_SPREADDATA;
-	is_modified = false;
-}
-
-SpreadWin::~SpreadWin()
-{
-	int i;
-
-	if(parent) {
-		if(cButtons) {
-			for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
-			free(cButtons);
-			}
-		if(rButtons) {
-			for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
-			free(rButtons);
-			}
-		if (aButton) delete(aButton);
-		if (w) delete w;
-		if (g && NumGraphs) {
-			for(i = 0; i < NumGraphs; i++) if(g[i]) delete(g[i]);
+	is_modified = bDoColWidth = false;
+}
+
+SpreadWin::~SpreadWin()
+{
+	int i;
+
+	if(parent) {
+		if(cButtons) {
+			for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
+			free(cButtons);
+			}
+		if(rButtons) {
+			for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
+			free(rButtons);
+			}
+		if (aButton) delete(aButton);
+		if (w) delete w;
+		if (g && NumGraphs) {
+			for(i = 0; i < NumGraphs; i++) if(g[i]) delete(g[i]);
 			free (g);
 			}
 		if(filename) free(filename);	filename=0L;
@@ -202,25 +207,25 @@ SpreadWin::~SpreadWin()
 }
 
 void
-SpreadWin::DoPlot(anyOutput *o)
-{
-	o->ActualSize(&currRC);
-	o->StartPage();
-	d->Command(CMD_DOPLOT, (void*)this, o);
-	o->EndPage();
-}
-
-bool
-SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	char *Name;
-	Graph *g2;
-	int i, j, k;
+SpreadWin::DoPlot(anyOutput *o)
+{
+	o->ActualSize(&currRC);
+	o->StartPage();
+	d->Command(CMD_DOPLOT, (void*)this, o);
+	o->EndPage();
+}
+
+bool
+SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	char *Name;
+	Graph *g2;
+	int i, j, k;
 	MouseEvent *mev;
-	POINT p1;
-
+	POINT p1;
+
 	if(d) {
-		if(!o) o = w;
+		if(!o) o = w;
 		switch(cmd) {
 		case CMD_CURRPOS:
 			if(tmpl && cButtons && rButtons) {
@@ -231,7 +236,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 						cButtons[i]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
 						}
 					urc.left = cButtons[0]->rDims.left;		urc.bottom = cButtons[0]->rDims.bottom;
-					urc.top = cButtons[0]->rDims.top;		urc.right = urc.left + cw * (i-1);
+					urc.top = cButtons[0]->rDims.top;		urc.right = urc.left + d->ri->GetWidth(i+ssOrg.x) * (i-1);
 					w->UpdateRect(&urc, false);
 					}
 				if(((POINT*)tmpl)->y != cpos.y) {
@@ -239,15 +244,16 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 						rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
 						}
 					urc.left = rButtons[0]->rDims.left;		urc.right = rButtons[0]->rDims.right;
-					urc.top = rButtons[0]->rDims.top;		urc.bottom = urc.top + ch * (i-1);
+					urc.top = rButtons[0]->rDims.top;		urc.bottom = urc.top + d->ri->GetHeight(i+ssOrg.y) * (i-1);
 					w->UpdateRect(&urc, false);
 					}
 				}
-			return true;
+			return true;
 		case CMD_CAN_CLOSE:
 			HideTextCursor();
 			if(is_modified == true) {
 				is_modified=false;
+				if(Undo.isEmpty(0L)) return true;
 				i = YesNoCancelBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?");
 				if(i == 2) return false;
 				else if(i == 1) return Command(CMD_SAVEDATAAS, tmpl, o);
@@ -258,7 +264,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 		case CMD_WRITE_GRAPHS:
 			if (g && NumGraphs) WriteGraphXML((unsigned char**)tmpl, (long*)o);
 			return true;
-		case CMD_DROP_GRAPH:
+		case CMD_DROP_GRAPH:
 			if(!tmpl) return false;				if(o) o->FileHistory();
 			if(g && NumGraphs) {
 				if(g = (Graph**)realloc(g, (NumGraphs+2) * sizeof(Graph*)))
@@ -279,25 +285,25 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			NumGraphs = j;	g[j-1]->DoPlot(0L);
 			return true;
-		case CMD_NEWGRAPH:
-			if((g2 = new Graph(this, d, 0L)) && g2->PropertyDlg() && 
-				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
+		case CMD_NEWGRAPH:
+			if((g2 = new Graph(this, d, 0L)) && g2->PropertyDlg() && 
+				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
+			else if(g2) DeleteGO(g2);
+			Undo.SetDisp(w);
+			return false;
+		case CMD_NEWPAGE:
+			if((g2 = new Page(this, d)) && 
+				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
 			else if(g2) DeleteGO(g2);
-			Undo.SetDisp(w);
-			return false;
-		case CMD_NEWPAGE:
-			if((g2 = new Page(this, d)) && 
-				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
-			else if(g2) DeleteGO(g2);
 			Undo.SetDisp(w);
-			return false;
-		case CMD_DELGRAPH:
-			if (g && NumGraphs) {
-				for(i = 0; i < NumGraphs; i++) if(g[i]) DeleteGO(g[i]);
-				free (g);
-				}
-			g = 0L;			NumGraphs = 0;		Undo.Flush();
-			return true;
+			return false;
+		case CMD_DELGRAPH:
+			if (g && NumGraphs) {
+				for(i = 0; i < NumGraphs; i++) if(g[i]) DeleteGO(g[i]);
+				free (g);
+				}
+			g = 0L;			NumGraphs = 0;		Undo.Flush();
+			return true;
 		case CMD_DELOBJ:
 			i = j = 0;
 			if(g && tmpl) for(; i < NumGraphs; i++) {
@@ -314,85 +320,150 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 				is_modified=false;
 				if(o) o->MouseCursor(MC_ARROW, false);
 				return true;
-				}
+				}
 			if(o) o->MouseCursor(MC_ARROW, true);
 		case CMD_SAVEDATAAS:
-			is_modified=false;
-			if((Name = SaveDataAsName(filename)) && Name[0]){
-				if(o) o->FileHistory();
-				if(Name && d->WriteData(Name)) {
-					if(filename) free(filename);		filename = strdup(Name);
+			is_modified=false;
+			if((Name = SaveDataAsName(filename)) && Name[0]){
+				if(o) o->FileHistory();
+				if(Name && d->WriteData(Name)) {
+					if(filename) free(filename);		filename = _strdup(Name);
 					}
-				else return false;
+				else return false;
 				}
-			else return false;
-			return true;
+			else return false;
+			return true;
 		case CMD_DROPFILE:
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
-			if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L, false);
-			else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
-				if(filename) free(filename);			filename = strdup((char*)tmpl);
-				return Command(CMD_SETSCROLL, 0L, w);
-				}
-			return false;
-		case CMD_OPEN:
+			if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L, false);
+			else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
+				if(filename) free(filename);			filename = _strdup((char*)tmpl);
+				return Command(CMD_SETSCROLL, 0L, w);
+				}
+			return false;
+		case CMD_OPEN:
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
-			if((Name = OpenDataName(filename)) && Name[0]){
-				if(o) o->FileHistory();
-				if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L, false);
-				else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
-					if(filename) free(filename);		filename = strdup(Name);
-					return Command(CMD_SETSCROLL, 0L, w);
-					}
-				}
-			return false;
-		case CMD_ADDROWCOL:
+			Undo.KillDisp(o);
+			Undo.SetDisp(o);
+			if((Name = OpenDataName(filename)) && Name[0]){
+				if(o) o->FileHistory();
+				if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L, false);
+				else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
+					if(filename) free(filename);		filename = _strdup(Name);
+					return Command(CMD_SETSCROLL, 0L, w);
+					}
+				}
+			return false;
+		case CMD_ADDROWCOL:
 			if(DoSpShSize(d)) DoPlot(o);
-			return true;
-		case CMD_MOUSE_EVENT:
+			return true;
+		case CMD_COL_MOUSE:
 			if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
-				if(mev->x < fw && mev->y < (o->MenuHeight + ch) && aButton) {
+				for(i = 0; cButtons[i]; i++){
+					if(bDoColWidth) {
+						o->MouseCursor(MC_EAST, false);
+						}
+					else if(mev->x > cButtons[i]->rDims.left && mev->x < cButtons[i]->rDims.right+2){
+						if(mev->x > cButtons[i]->rDims.right-4) {
+							o->MouseCursor(MC_EAST, false);
+							switch(mev->Action) {
+							case MOUSE_LBDOWN:
+								CurrCol = i;					line[0].x = line[1].x = mev->x;
+								line[0].y = o->MenuHeight;		line[1].y = currRC.bottom;
+								d->Command(CMD_TOOLMODE, tmpl, o);
+								return bDoColWidth = true;
+								}
+							}
+						else o->MouseCursor(MC_ARROW, false);
+						return false;
+						}
+					else o->MouseCursor(MC_ARROW, false);
+					if(mev->Action == MOUSE_MOVE && bDoColWidth && (mev->StateFlags & 0x01)) {
+						rc_line.left = line[0].x - 2;		rc_line.right = line[1].x + 2;
+						rc_line.top = line[0].y - 2;		rc_line.bottom = line[1].y +2;
+						o->UpdateRect(&rc_line, false);
+						if(mev->x < (cButtons[CurrCol]->rDims.left +20))mev->x = cButtons[CurrCol]->rDims.left +20;
+						k = mev->x - cButtons[CurrCol]->rDims.right;
+						for(j = CurrCol; cButtons[j] && cButtons[j]->rDims.left < (currRC.right-k); j++) {
+							cButtons[j]->rDims.right += k;	cButtons[j]->rDims.left += j > CurrCol ? k : 0;
+							cButtons[j]->DoPlot(o);			o->UpdateRect(&cButtons[j]->rDims, false);
+							cButtons[j]->rDims.right -= k;	cButtons[j]->rDims.left -= j > CurrCol ? k : 0;
+							}
+						line[0].x = line[1].x = mev->x;
+						line[0].y = o->MenuHeight;			line[1].y = currRC.bottom;
+						o->ShowLine(line, 2, 0x00a0a0a0);
+						return true;
+						}
+					if(mev->Action == MOUSE_LBUP && bDoColWidth) {
+						bDoColWidth = false;
+						k = line[0].x - cButtons[CurrCol]->rDims.left;
+						if(abs(k - cButtons[CurrCol]->rDims.right + cButtons[CurrCol]->rDims.left)>3) {
+#ifdef USE_WIN_SECURE
+							sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s1:%s1", Int2ColLabel(CurrCol + ssOrg.x, false), Int2ColLabel(CurrCol + ssOrg.x, false));
+#else
+							sprintf(TmpTxt, "%s1:%s1", Int2ColLabel(CurrCol + ssOrg.x, false), Int2ColLabel(CurrCol + ssOrg.x, false));
+#endif
+							d->ri = new RangeInfo(1, TmpTxt, d->ri);
+							d->ri->SetWidth(k >=20 ? k : 20);
+							}
+						d->Command(CMD_REDRAW, 0L, o);
+						return true;
+						}
+					else bDoColWidth = false;
+					}
+				}
+			else o->MouseCursor(MC_ARROW, false);
+			return false;
+		case CMD_MOUSE_EVENT:
+			if(!tmpl) return false;
+			if(bDoColWidth)return Command(CMD_COL_MOUSE, tmpl, o);
+			if((mev = (MouseEvent*)tmpl)->y < o->MenuHeight) o->MouseCursor(MC_ARROW, false); 
+			else if(o && cButtons && rButtons) {
+				if(mev->x < d->ri->GetFirstWidth() && mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && aButton) {
 					aButton->Command(cmd, tmpl, o);
-					}
-				else if(mev->x < fw && rButtons) {
-					i = (mev->y - o->MenuHeight - ch)/ch;
-					if(rButtons[i]) rButtons[i]->Command(cmd, tmpl, o);
-					}
-				else if(mev->y < (o->MenuHeight + ch) && cButtons) {
-					i = (mev->x - fw)/cw;
-					if(cButtons[i]) cButtons[i]->Command(cmd, tmpl, o);
-					}
-				else if(o->MrkMode == MRK_SSB_DRAW) o->HideMark();
+					}
+				else if(mev->x < d->ri->GetFirstWidth() && rButtons) {
+					i = (mev->y - o->MenuHeight - d->ri->GetHeight(-1))/d->ri->GetHeight(-1);
+					if(rButtons[i]) rButtons[i]->Command(cmd, tmpl, o);
+					}
+				else if(mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && cButtons) {
+					i = (mev->x - d->ri->GetFirstWidth())/d->ri->GetWidth(-1);
+					if(cButtons[i]) cButtons[i]->Command(cmd, tmpl, o);
+					}
+				else if(o->MrkMode == MRK_SSB_DRAW) o->HideMark();
 				}
 			return	d->Command(cmd, tmpl, o);
 		case CMD_PASTE_TSV:		case CMD_PASTE_CSV:		case CMD_PASTE_SSV:
 			Undo.DataObject(this, w, d, 0L, 0L);
-		case CMD_COPY_SYLK:		case CMD_ADDCHAR:		case CMD_SHIFTUP:
-		case CMD_COPY_TSV:		case CMD_COPY_XML:		case CMD_QUERY_COPY:
-		case CMD_TAB:			case CMD_SHTAB:			case CMD_SHIFTDOWN:
-		case CMD_CURRLEFT:		case CMD_CURRIGHT:		case CMD_CURRUP:
-		case CMD_CURRDOWN:		case CMD_SHIFTRIGHT:	case CMD_POS_FIRST:
-		case CMD_POS_LAST:		case CMD_SHIFTLEFT:		case CMD_DELETE:
+		case CMD_COPY_SYLK:		case CMD_ADDCHAR:		case CMD_SHIFTUP:
+		case CMD_COPY_TSV:		case CMD_COPY_XML:		case CMD_QUERY_COPY:
+		case CMD_TAB:			case CMD_SHTAB:			case CMD_SHIFTDOWN:
+		case CMD_CURRLEFT:		case CMD_CURRIGHT:		case CMD_CURRUP:
+		case CMD_CURRDOWN:		case CMD_SHIFTRIGHT:	case CMD_POS_FIRST:
+		case CMD_POS_LAST:		case CMD_SHIFTLEFT:		case CMD_DELETE:
 		case CMD_TOOLMODE:		case CMD_FILLRANGE:		case CMD_CUT:
 		case CMD_PASTE_XML:		case CMD_DELROW:		case CMD_INSROW:
-		case CMD_INSCOL:		case CMD_DELCOL:		case CMD_UNDO:
+		case CMD_INSCOL:		case CMD_DELCOL:		case CMD_UNDO:
 		case CMD_SHPGUP:		case CMD_SHPGDOWN:
+			bDoColWidth = false;
 			return d->Command(cmd, tmpl, o);
 		case CMD_REDRAW:
 			Undo.SetDisp(w);						d->Command(cmd, tmpl, o);
-			return true;
+			return true;
 		case CMD_MOUSECURSOR:
 			if(o)o->MouseCursor(MC_ARROW, false);	
 			return true;
-		case CMD_SETSCROLL:
-			HideTextCursor();						o->ActualSize(&currRC);
-			k = (currRC.bottom-currRC.top)/ch;		d->GetSize(&i, &j);
-			o->SetScroll(true, 0, j, k, ssOrg.y);	k = (currRC.right-currRC.left)/cw;
-			o->SetScroll(false, 0, i, k, ssOrg.x);	DoPlot(o);
-			return true;
-		case CMD_PAGEUP:		case CMD_PAGEDOWN:
-			k = (currRC.bottom-currRC.top)/ch;
-			k = k > 3 ? k-2 : 1;					p1.x = fw + 2;		p1.y = ch + 2;
+		case CMD_SETSCROLL:
+			HideTextCursor();						o->ActualSize(&currRC);
+			k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
+			d->GetSize(&i, &j);
+			o->SetScroll(true, 0, j, k, ssOrg.y);	k = (currRC.right-currRC.left)/d->ri->GetWidth(-1);
+			o->SetScroll(false, 0, i, k, ssOrg.x);	DoPlot(o);
+			return true;
+		case CMD_PAGEUP:		case CMD_PAGEDOWN:
+			k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
+			k = k > 3 ? k-2 : 1;					p1.x = d->ri->GetFirstWidth() + 2;
+			p1.y = d->ri->GetHeight(-1) + 2;
 			if(CurrText){
 				p1.x = CurrText->GetX()+2;	p1.y = CurrText->GetY()+12;
 				}
@@ -401,108 +472,108 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			else ssOrg.y = ssOrg.y < j-k*2 ? ssOrg.y+k : j > k ? j-k : 0;
 			Command(CMD_SETSCROLL, tmpl, o);
 			CurrText = 0L;		d->Select(&p1);
-			return true;
-		case CMD_SETHPOS:
-			ssOrg.x = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
-			return Command(CMD_SETSCROLL, tmpl, o);
-		case CMD_SETVPOS:
-			ssOrg.y = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
-			return Command(CMD_SETSCROLL, tmpl, o);
+			return true;
+		case CMD_SETHPOS:
+			ssOrg.x = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
+			return Command(CMD_SETSCROLL, tmpl, o);
+		case CMD_SETVPOS:
+			ssOrg.y = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
+			return Command(CMD_SETSCROLL, tmpl, o);
 		case CMD_SETFOCUS:
-			Undo.SetDisp(w);
-			return true;
-		case CMD_KILLFOCUS:
-			return true;
-		case CMD_TEXTSIZE:
-			if(tmpl)ssText.iSize = *((int*)tmpl);
-			return true;
-		case CMD_CONFIG:
+			Undo.SetDisp(w);
+			return true;
+		case CMD_KILLFOCUS:
+			return true;
+		case CMD_TEXTSIZE:
+			if(tmpl)ssText.iSize = *((int*)tmpl);
+			return true;
+		case CMD_CONFIG:
 			if(defs.PropertyDlg()) return Command(CMD_REDRAW, 0L, o);
 			return false;
-		case CMD_NONE:
-			return true;
-		case CMD_PRINT:
-			return PrintData(o);
-			}
-		}
-	return false;
-}
-
-bool
-SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
-{
-	int i, c, nr, nc, ac = 1, na = 0;
-	RECT rc;
+		case CMD_NONE:
+			return true;
+		case CMD_PRINT:
+			return PrintData(o);
+			}
+		}
+	return false;
+}
+
+bool
+SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
+{
+	int i, c, nr, nc, cx, cw, ac = 1, na = 0;
+	RECT rc;
 	char text[20];
-	POINT grid[2];
-	TextDEF ButtText;
-	bool redim = false;
-
-	cpos.x = cp->x;			cpos.y = cp->y;
-	if(ch != CellHeight || cw != CellWidth || fw != FirstWidth) redim = true;
-	ch = CellHeight;	cw = CellWidth;		fw = FirstWidth;
-	if(redim){
-		if(cButtons) {
-			for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
-			free(cButtons);
-			}
-		if(rButtons) {
-			for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
-			free(rButtons);
-			}
-		if(aButton) delete(aButton);		aButton = 0L;
-		cButtons = rButtons = 0L;
+	TextDEF ButtText;
+	bool redim = bDoColWidth;
+
+	w->HideMark();
+	cpos.x = cp->x;			cpos.y = cp->y;
+	if(d->ri->GetHeight(-1) != CellHeight || d->ri->GetWidth(-1) != CellWidth || d->ri->GetFirstWidth() != FirstWidth) redim = true;
+	if(redim){
+		d->ri->SetHeight(CellHeight);		d->ri->SetDefWidth(CellWidth);		d->ri->SetFirstWidth(FirstWidth);
+		if(cButtons) {
+			for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
+			free(cButtons);
+			}
+		if(rButtons) {
+			for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
+			free(rButtons);
+			}
+		if(aButton) delete(aButton);		aButton = 0L;
+		cButtons = rButtons = 0L;
 		}
 	if(!aButton) aButton = new ssButton(this, 0, w->MenuHeight, FirstWidth, CellHeight);
-	memcpy(&ButtText, &ssText, sizeof(TextDEF));
-	ButtText.Align = TXA_HCENTER | TXA_VCENTER;
-	w->GetSize(&rc);
-	if(!cButtons) {
-		c = (rc.right/CellWidth)+1;
-		cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
-		for(i = 0; i < (c-1); i++) cButtons[i] = 
-			new ssButton(this, i*CellWidth+FirstWidth, w->MenuHeight, 
-			CellWidth+1, CellHeight);
-		}
-	if(!rButtons) {
- 		c = (rc.bottom/CellHeight)+1;
-		rButtons = (ssButton**)calloc(c, sizeof(ssButton*));
-		for(i = 0; i < (c-1); i++) rButtons[i] = 
-			new ssButton(this, 0, i*CellHeight+CellHeight+w->MenuHeight, 
-			FirstWidth, CellHeight);
-		}
-	w->SetLine((LineDEF *)&GrayLine);
-	d->GetSize(&nc, &nr);
-	grid[0].x = rc.left+FirstWidth;
-	i = (nc-ssOrg.x)*CellWidth+FirstWidth;
-	grid[1].x = i < rc.right ? i : rc.right;
-	if(rButtons) for(i = 0; rButtons[i]; i++) {
-		sprintf(text, "%d", i+1+ssOrg.y);
-		if(rButtons[i]) {
-			rButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
-			rButtons[i]->Command(CMD_SETTEXT, text, w);
+	memcpy(&ButtText, &ssText, sizeof(TextDEF));
+	ButtText.Align = TXA_HCENTER | TXA_VCENTER;
+	w->GetSize(&rc);
+	if(!cButtons) {
+		c = ((rc.right/CellWidth)<<2) +1;
+		cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
+		for(i = 0, cx = FirstWidth; i < (c-1); i++) {
+			cw = d->ri->GetWidth(i+ssOrg.x);
+			cButtons[i] = new ssButton(this, cx, w->MenuHeight, cw+1, CellHeight);
+			cx += cw;
+			}
+		}
+	else {
+		for(i = 0, cx = FirstWidth; cButtons[i]; i++) {
+			cw = d->ri->GetWidth(i+ssOrg.x);
+			cButtons[i]->rDims.left = cx;		cButtons[i]->rDims.right = cx + cw + 1;
+			cx += cw;
+			}
+		}
+	if(!rButtons) {
+ 		c = (rc.bottom/CellHeight)+1;
+		rButtons = (ssButton**)calloc(c, sizeof(ssButton*));
+		for(i = 0; i < (c-1); i++) rButtons[i] = 
+			new ssButton(this, 0, i*CellHeight+CellHeight+w->MenuHeight, 
+			FirstWidth, CellHeight);
+		}
+	d->GetSize(&nc, &nr);
+	if(rButtons) for(i = 0; rButtons[i]; i++) {
+#ifdef USE_WIN_SECURE
+		sprintf_s(text, 20, "%d", i+1+ssOrg.y);
+#else
+		sprintf(text, "%d", i+1+ssOrg.y);
+#endif
+		if(rButtons[i]) {
+			rButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
+			rButtons[i]->Command(CMD_SETTEXT, text, w);
 			rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
-			w->SetLine((LineDEF *)&GrayLine);
-			}
-		grid[0].y = grid[1].y = w->MenuHeight + i*CellHeight - 1;
-		if(i < (2+nr-ssOrg.y)) w->oSolidLine(grid);
-		}
-	grid[0].y = rc.top+CellHeight+w->MenuHeight;
-	i = (1+nr-ssOrg.y)*CellHeight;
-	grid[1].y = (i+w->MenuHeight)< rc.bottom ? i+w->MenuHeight : rc.bottom;
-	if(cButtons) for(i = 0; cButtons[i]; i++) {
-		if(cButtons[i]) {
-			cButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
-			cButtons[i]->Command(CMD_SETTEXT, Int2ColLabel(i+ssOrg.x, true), w);
-			cButtons[i]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
-			w->SetLine((LineDEF *)&GrayLine);
-			}
-		grid[0].x = grid[1].x = i*CellWidth+FirstWidth-1;
-		if(i <= (nc-ssOrg.x)) w->oSolidLine(grid);
+			}
+		}
+	if(cButtons) for(i = 0; cButtons[i]; i++) {
+		if(cButtons[i]) {
+			cButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
+			cButtons[i]->Command(CMD_SETTEXT, Int2ColLabel(i+ssOrg.x, true), w);
+			cButtons[i]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
+			}
 		}
 	w->SetTextSpec(&ssText);
-	if(aButton) aButton->DoPlot(w);
-	return true;
+	if(aButton) aButton->DoPlot(w);
+	return true;
 }
 
 void
@@ -535,187 +606,213 @@ SpreadWin::MarkButtons(char *rng, POINT *cp)
 		for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SELECT, r == i ? &r_idx[1] : &r_idx[0], w);
 		}
 	free(r_idx);		free(c_idx);
-}
-
-bool
-SpreadWin::PrintData(anyOutput *o)
-{
-	int i, j, k, l, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
+}
+
+bool
+SpreadWin::PrintData(anyOutput *o)
+{
+	int i, j, k, l, pgw, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
 	int row, col, width, height, ipad;
-	double scale;
-	RECT rc, margin, margin_first;
-	POINT pp_pos, ss_pos, grid[2];
-	LineDEF Line1, Line2;
-	TextDEF td, tdp;
-	bool bContinue;
-	time_t ti = time(0L);
-	anyResult res;
-
-	Line1.patlength = Line2.patlength = 1.0;
-	Line1.color = Line2.color = 0x0;			//black gridlines
-	Line1.pattern = Line2.pattern = 0x0;		//solid lines
-	switch(defs.cUnits) {
-	case 1:		Line1.width = 0.01;			break;
-	case 2:		Line1.width = 0.003937;		break;
-	default:	Line1.width = 0.1;			break;
-		}
+	double scale;
+	RECT rc, margin, margin_first;
+	POINT pp_pos, ss_pos, grid[3];
+	LineDEF Line1, Line2;
+	TextDEF td, tdp;
+	bool bContinue;
+	time_t ti = time(0L);
+	anyResult res;
+
+	Line1.patlength = Line2.patlength = 1.0;
+	Line1.color = Line2.color = 0x00808080;		//gray gridlines
+	Line1.pattern = Line2.pattern = 0x0;		//solid lines
+	switch(defs.cUnits) {
+	case 1:		Line1.width = 0.01;			break;
+	case 2:		Line1.width = 0.003937;		break;
+	default:	Line1.width = 0.1;			break;
+		}
 #ifdef _WINDOWS
 	scale = 1.0/_SQRT2;
 #else
 	scale = 0.9;
 #endif
-	Line2.width = Line1.width * 3.0;
-	d->GetSize(&nc, &nr);
-	if(!(o->StartPage())) return false;
-	pfw = iround(o->hres * ((double)fw)/w->hres * scale);
-	pcw = iround(o->hres * ((double)cw)/w->hres * scale);
-	pch = iround((o->vres * ((double)ch)/w->vres) * scale + o->vres/20.0);
-	o->ActualSize(&rc);
-	tdp.ColTxt = 0x0;	tdp.ColBg = 0x00ffffffL; 
-	tdp.fSize = tdp.RotBL = tdp.RotCHAR = 0.0;	tdp.Align = TXA_HRIGHT | TXA_VCENTER;
-#ifdef _WINDOWS
-	tdp.iSize = iround(o->hres/6.0);
-#else
-	tdp.iSize = iround(o->hres/7.5);
-#endif
-	tdp.Mode = TXM_TRANSPARENT;
-	tdp.Style = TXS_NORMAL;				tdp.Font = FONT_HELVETICA;	tdp.text = 0L;
-	memcpy(&td, &ssText, sizeof(TextDEF));	
-	td.Align = TXA_HCENTER | TXA_VCENTER;	
-	td.Style = TXS_NORMAL;	td.iSize = 0;
-#ifdef _WINDOWS
-	td.fSize = defs.GetSize(SIZE_CELLTEXT);
-#else
-	td.fSize = defs.GetSize(SIZE_CELLTEXT)*.8;
-#endif
-	margin.left = iround(o->hres);	margin.right = iround(o->hres/2.0);
-	margin.top = margin.bottom = iround(o->hres);
-	memcpy(&margin_first, &margin, sizeof(RECT));
-	cpp = (rc.right - margin.left - margin.right - pfw)/pcw;
-	rpp = (rc.bottom - margin.top - margin.bottom - pch)/pch;
-	pp_pos.x = margin.left;		pp_pos.y = margin.top;
-	ss_pos.x = 0;				ss_pos.y = 0;		cpages = 1;
-	do {
-		pp_pos.x = margin.left;		pp_pos.y = margin.top;
-		k = (ss_pos.x + cpp) > nc ? nc-ss_pos.x : cpp;
-		l = (ss_pos.y + rpp) > nr ? nr-ss_pos.y : rpp;
-		grid[0].y = margin.top +pch; grid[1].y = grid[0].y + l * pch;
-		o->SetLine(&Line2);
-		grid[0].x = grid[1].x = pp_pos.x;		o->oSolidLine(grid);
-		grid[0].x = grid[1].x = pp_pos.x+pfw;	o->oSolidLine(grid);
-		o->SetLine(&Line1);
-		for(i = 1; i <= k; i++) {			//vertical grid
-			grid[0].x = grid[1].x = pp_pos.x + pfw + i * pcw;
-			o->oSolidLine(grid);
-			}
-		grid[0].x = margin.left+pfw;	grid[1].x = grid[0].x + k * pcw;
-		o->SetLine(&Line2);
-		grid[0].y = grid[1].y = pp_pos.y;		o->oSolidLine(grid);
-		grid[0].y = grid[1].y = pp_pos.y+pch;	o->oSolidLine(grid);
-		o->SetLine(&Line1);
-		for(i = 1; i <= l; i++) {			//horizontal grid
-			grid[0].y = grid[1].y = pp_pos.y + pch + i * pch;
-			o->oSolidLine(grid);
-			}
-		o->SetLine(&Line2);
-		td.Align = TXA_HCENTER | TXA_VCENTER;	o->SetTextSpec(&td);
-		grid[0].y = margin.top;	 grid[1].y = grid[0].y + pch;
-		iy = margin.top + (pch >>1);
-		for(i = 0; i <= k; i++) {			//column headers
-			grid[0].x = grid[1].x = pp_pos.x + pfw + i * pcw;
-			o->oSolidLine(grid);			ix = grid[0].x + (pcw >>1);
-			if(i < k) o->oTextOut(ix, iy, Int2ColLabel(i+ss_pos.x, true), 0);
-			}
-		td.Align = TXA_HRIGHT | TXA_VCENTER;	
-		o->SetTextSpec(&td);	ix = margin.left + pfw - iround(o->hres/20.0);
-		grid[0].x = margin.left;	grid[1].x = grid[0].x + pfw;
-		for(i = 0; i <= l; i++) {			//row labels
-			grid[0].y = grid[1].y = pp_pos.y + pch + i * pch;
-			o->oSolidLine(grid);	iy = grid[0].y + (pch >>1);
-			sprintf(TmpTxt, "%d", i+1+ss_pos.y);
-			if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
-			}
-		ipad = iround(o->hres/20.0);
-		for(i = 0; i < k; i++) {			//spreadsheet data
+	Line2.width = Line1.width * 3.0;
+	d->GetSize(&nc, &nr);
+	if(!(o->StartPage())) return false;
+	pfw = iround(o->hres * ((double)d->ri->GetFirstWidth())/w->hres * scale);
+	pcw = iround(o->hres * ((double)d->ri->GetWidth(-1))/w->hres * scale);
+	pch = iround((o->vres * ((double)d->ri->GetHeight(-1))/w->vres) * scale + o->vres/20.0);
+	o->ActualSize(&rc);
+	tdp.ColTxt = 0x0;	tdp.ColBg = 0x00ffffffL; 
+	tdp.fSize = tdp.RotBL = tdp.RotCHAR = 0.0;	tdp.Align = TXA_HRIGHT | TXA_VCENTER;
+	tdp.Mode = TXM_TRANSPARENT;
+	tdp.Style = TXS_NORMAL;				tdp.Font = FONT_HELVETICA;	tdp.text = 0L;
+	memcpy(&td, &ssText, sizeof(TextDEF));	
+	td.Align = TXA_HCENTER | TXA_VCENTER;	
+	td.Style = TXS_NORMAL;	td.iSize = 0;
+#ifdef _WINDOWS
+	tdp.iSize = iround(o->hres/6.0);
+	td.fSize = defs.GetSize(SIZE_CELLTEXT);
+#else
+	tdp.iSize = iround(o->hres/7.5);
+	td.fSize = defs.GetSize(SIZE_CELLTEXT)*.8;
+#endif
+	margin.left = iround(o->hres);	margin.right = iround(o->hres/2.0);
+	margin.top = margin.bottom = iround(o->hres);
+	memcpy(&margin_first, &margin, sizeof(RECT));
+	pp_pos.x = margin.left;		pp_pos.y = margin.top;
+	ss_pos.x = 0;				ss_pos.y = 0;		cpages = 1;
+	rpp = (rc.bottom - margin.top - margin.bottom - pch)/pch;
+	do {
+		k = (rc.right - margin.left - margin.right - pfw);
+		for(i = pgw = 0; pgw < k && (i+ss_pos.x) < nc; i++ ){
+			pgw += (pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale));
+			if(i >=(nc-1)) break;
+			}
+		if(pgw < k) {
+			cpp = i+1;
+			}
+		else {
+			cpp = i-1;		pgw -= pcw;
+			}
+		pp_pos.x = margin.left;		pp_pos.y = margin.top;
+		k = (ss_pos.x + cpp) > nc ? nc-ss_pos.x : cpp;
+		l = (ss_pos.y + rpp) > nr ? nr-ss_pos.y : rpp;
+		grid[0].y = margin.top +pch; grid[1].y = grid[0].y + l * pch;
+		o->SetLine(&Line2);
+		grid[0].x = grid[1].x = pp_pos.x;		o->oSolidLine(grid);
+		grid[0].x = grid[1].x = pp_pos.x+pfw;	o->oSolidLine(grid);
+		grid[0].x = margin.left+pfw;	grid[1].x = grid[0].x + pgw;
+		o->SetLine(&Line2);
+		grid[0].y = grid[1].y = pp_pos.y;		o->oSolidLine(grid);
+		grid[0].y = grid[1].y = pp_pos.y+pch;	o->oSolidLine(grid);
+		o->SetLine(&Line2);
+		td.Align = TXA_HCENTER | TXA_VCENTER;	o->SetTextSpec(&td);
+		grid[0].y = margin.top;	 grid[1].y = grid[0].y + pch;
+		iy = margin.top + (pch >>1);	grid[0].x = grid[1].x = pp_pos.x + pfw;
+		for(i = 0, ix = pp_pos.x + pfw; i <= k; i++) {			//column headers
+			pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
+			o->oSolidLine(grid);		grid[0].x = grid[1].x = ix + pcw;
+			if(i < k) o->oTextOut(ix + (pcw >>1), iy, Int2ColLabel(i+ss_pos.x, true), 0);
+			ix += pcw;
+			}
+		td.Align = TXA_HRIGHT | TXA_VCENTER;	
+		o->SetTextSpec(&td);	ix = margin.left + pfw - iround(o->hres/20.0);
+		grid[0].x = margin.left;		grid[1].x = grid[0].x + pfw;
+		for(i = 0; i <= l; i++) {			//row labels
+			grid[0].y = grid[1].y = pp_pos.y + pch + i * pch;
+			o->oSolidLine(grid);		iy = grid[0].y + (pch >>1);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d", i+1+ss_pos.y);
+#else
+			sprintf(TmpTxt, "%d", i+1+ss_pos.y);
+#endif
+			if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
+			}
+		ipad = iround(o->hres/30.0);
+		grid[0].x = margin.left+pfw + ipad;
+		for(i = 0; i < k; i++, grid[0].x += pcw) {			//spreadsheet data
+			pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
 			for (j = 0; j < l; j++) {
 				row = j+ss_pos.y;		col = i+ss_pos.x;
 				if(row >= 0 && row < d->cRows && col >= 0  && col < d->cCols && d->etRows[row][col]) {
 					d->etRows[row][col]->GetResult(&res, false);
 					TranslateResult(&res);
 					td.Align = TXA_HLEFT | TXA_VCENTER;
-					ix = margin.left+pfw + i*pcw + ipad;
+					ix = grid[0].x;
 					switch (res.type) {
 					case ET_VALUE:
-						ix = margin.left+pfw+pcw + i*pcw - ipad;
+						ix = ix + pcw - ( ipad<<1 );
 						td.Align = TXA_HRIGHT | TXA_VCENTER;
-						strcpy(TmpTxt, res.text);
+						rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text);
 						fit_num_rect(o, pcw - ipad, TmpTxt);
 						Int2Nat(TmpTxt);			break;
 					case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
-						ix = margin.left+pfw+pcw + i*pcw - ipad;
+						ix = ix + pcw - ( ipad<<1 );
 						td.Align = TXA_HRIGHT | TXA_VCENTER;
 					case ET_TEXT:	case ET_UNKNOWN:
-						if(res.text && strlen(res.text) < 40) 
-							strcpy(TmpTxt, res.text[0] != '\'' ? res.text : res.text +1);
-						else if(res.text) sprintf(TmpTxt,"#SIZE");
+						if(res.text&& strlen(res.text) < 40) 
+							rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text[0] != '\'' ? res.text : res.text +1);
+						else if(res.text) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#SIZE");
 						else TmpTxt[0] = 0;	
 						do {
-							o->oGetTextExtent(TmpTxt, strlen(TmpTxt), &width, &height);
+							o->oGetTextExtent(TmpTxt, (int)strlen(TmpTxt), &width, &height);
 							if(width > (pcw + iround(o->hres/20.0))) TmpTxt[strlen(TmpTxt)-1] = 0;
 							}while(width > (pcw + ipad));
 						break;
 					case ET_ERROR:
-						strcpy(TmpTxt, "#ERROR");	break;
+						rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#ERROR");	break;
 					default:
-						strcpy(TmpTxt, "#VALUE");	break;
+						rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#VALUE");	break;
 						}
 					iy = pp_pos.y + pch + (pch>>1) + j * pch;
 					o->SetTextSpec(&td);			o->oTextOut(ix, iy, TmpTxt, 0);
-					}
-				}
-			}
-		//prepare for next table
-		ss_pos.x += k;			bContinue = false;
-		if(ss_pos.x >= nc) {ss_pos.x = 0; ss_pos.y += l; }
-		if(ss_pos.y < nr) {
-			ix = pfw + (cpp % nc)*pcw + iround(o->hres/3.5);
-			iy = (l+2)*pch;
-			if((margin.left + ix + pfw + k*pcw) < (rc.right-margin.right)) {
-				margin.left += pfw + k*pcw + iround(o->hres/3.5);
-				bContinue = true;
-				}
-			else if((margin.top + iy + pch + l*pch) < (rc.bottom - margin.bottom)) {
-				margin.top += iy;	margin.left = margin_first.left;
-				bContinue = true;
-				}
-			else {
-				tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
-				sprintf(TmpTxt, "page %d", cpages++);
-				o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-				tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
-				sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
-				o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-				tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
-				sprintf(TmpTxt, "RLPlot %s", SZ_VERSION);
-				o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-				memcpy(&margin, &margin_first, sizeof(RECT));
-				bContinue = true;
-				o->Eject();
-				}
-			}
-		}while(bContinue);
-	tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
-	sprintf(TmpTxt, "page %d", cpages++);
-	o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-	tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
-	sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
-	o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-	tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
-	sprintf(TmpTxt, "RLPlot %s", SZ_VERSION);
-	o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
-	o->EndPage();
-	return true;
-}
+					grid[0].y = grid[1].y = iy+(pch>>1);	grid[2].y = grid[1].y - pch;
+					grid[0].x -= ipad;		grid[1].x = grid[2].x = grid[0].x + pcw;
+					o->SetLine(&Line1);		o->oPolyline(grid, 3, 0L);
+					grid[0].x += ipad;
+					}
+				}
+			}
+		//prepare for next table
+		ss_pos.x += k;			bContinue = false;
+		if(ss_pos.x >= nc) {ss_pos.x = 0; ss_pos.y += l; }
+		if(ss_pos.y < nr) {
+			ix = pfw + pgw + iround(o->hres/3.5);
+			iy = (l+2)*pch;
+			if((margin.left + ix + pfw + pgw) < (rc.right-margin.right)) {
+				margin.left += pfw + k*pcw + iround(o->hres/3.5);
+				bContinue = true;
+				}
+			else if((margin.top + iy + pch + l*pch) < (rc.bottom - margin.bottom)) {
+				margin.top += iy;	margin.left = margin_first.left;
+				bContinue = true;
+				}
+			else {
+				tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+				sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
+#else
+				sprintf(TmpTxt, "page %d", cpages++);
+#endif
+				o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+				tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+				ctime_s(TmpTxt, 24, &ti);
+#else
+				sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
+#endif
+				o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+				tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+				i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
+				rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, SZ_VERSION);
+				o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+				memcpy(&margin, &margin_first, sizeof(RECT));
+				bContinue = true;
+				o->Eject();
+				}
+			}
+		}while(bContinue);
+	tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+	sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
+#else
+	sprintf(TmpTxt, "page %d", cpages++);
+#endif
+	o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+	tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+	ctime_s(TmpTxt, 24, &ti);
+#else
+	sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
+#endif
+	o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+	tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
+	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, SZ_VERSION);
+	o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+	o->EndPage();
+	return true;
+}
 
 void 
 SpreadWin::WriteGraphXML(unsigned char **ptr, long *cbd)
@@ -728,290 +825,297 @@ SpreadWin::WriteGraphXML(unsigned char **ptr, long *cbd)
 		if((pg = (unsigned char*)GraphToMem(g[i], &cb)) && cb) {
 			newsize = *cbd + cb + 100;
 			*ptr = (unsigned char*)realloc(*ptr, newsize);
-			*cbd += sprintf(((char*)*ptr)+*cbd, "<Graph><![CDATA[\n");
-			*cbd += sprintf(((char*)*ptr)+*cbd, "%s", pg);
-			*cbd += sprintf(((char*)*ptr)+*cbd, "]]>\n</Graph>\n");
+			*cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "<Graph><![CDATA[\n");
+			memcpy(*ptr+ *cbd, pg, cb);		*cbd += cb;
+			*cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "]]>\n</Graph>\n");
 			if(pg) free(pg);		pg = 0L;			cb = 0;
 			}
 		}
 }
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// This data object is a spreadsheet
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class SpreadData:public DataObj{
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This data object is a spreadsheet
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SpreadData:public DataObj{
 typedef struct _pos_info {
 	POINT ssOrg, currpos;
 	void *CurrText;};
 
-public:
-	SpreadData(GraphObj *par);
-	~SpreadData();
-	bool Init(int nRows, int nCols);
-	bool mpos2dpos(POINT *mp, POINT *dp);
-	bool Select(POINT *p);
-	void MarkRange(char *range, POINT *cp = 0L);
-	void HideMark(bool cclp);
-	bool WriteData(char *FileName);
-	bool AddCols(int nCols);
+public:
+	SpreadData(GraphObj *par);
+	~SpreadData();
+	bool Init(int nRows, int nCols);
+	bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll);
+	bool Select(POINT *p);
+	void MarkRange(char *range, POINT *cp = 0L);
+	void HideMark(bool cclp);
+	bool WriteData(char *FileName);
+	bool AddCols(int nCols);
 	bool AddRows(int nRows);
 	bool ChangeSize(int nCols, int nRows, bool bUndo);
-	bool DeleteCols();
+	bool DeleteCols();
 	bool InsertCols();
 	bool DeleteRows();
 	bool InsertRows();
-	void DoPlot(anyOutput *o);
-	bool DelRange();
-	bool PasteRange(int cmd, char *txt);
+	void DoPlot(anyOutput *o);
+	bool DelRange();
+	bool PasteRange(int cmd, char *txt);
 	bool InitCopy(int cmd, void *tmpl, anyOutput *o);
-	bool SavePos();
-	bool Command(int cmd, void *tmpl, anyOutput *o);
-	bool ReadData(char *FileName, unsigned char *buffer, int type);
-
-	bool ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags = 0L);
-	bool ReadTSV(char *file, unsigned char *buffer, int type);
-	bool MemList(unsigned char **ptr, int type);
-
-private:
-	int CellHeight, CellWidth, FirstWidth, r_disp, c_disp, mrk_offs;
-	RECT cp_src_rec;			//bounding rectangle for copy range
-	bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
-	POINT currpos, currpos2;
-	anyOutput *w;
+	bool SavePos();
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool ReadData(char *FileName, unsigned char *buffer, int type);
+
+	bool ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags = 0L);
+	bool ReadTSV(char *file, unsigned char *buffer, int type);
+	bool MemList(unsigned char **ptr, int type);
+
+private:
+	int CellHeight, CellWidth, FirstWidth, r_disp, c_disp, mrk_offs;
+	RECT cp_src_rec;			//bounding rectangle for copy range
+	bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
+	POINT currpos, currpos2;
+	anyOutput *w;
 	SpreadWin *Disp;
 	GraphObj *g_parent;
-	EditText *et_racc;
-	char *m_range, *c_range;	//mark and copy ranges
+	EditText *et_racc;
+	char *m_range, *c_range;	//mark and copy ranges
 	char *err_msg, *last_err;	//error message
 	char *rlw_file;				//use this name for save
-	_pos_info pos_info;			//save position settings
-};
-
-SpreadData::SpreadData(GraphObj *par)
-{
-	Disp = 0L;	m_range = 0L;	c_range = 0L;	w = 0L;		err_msg=last_err=rlw_file =  0L;
+	_pos_info pos_info;			//save position settings
+};
+
+SpreadData::SpreadData(GraphObj *par)
+{
+	Disp = 0L;	m_range = 0L;	c_range = 0L;	w = 0L;		err_msg=last_err=rlw_file =  0L;
 	g_parent = par;		CellWidth = CellHeight = FirstWidth = 0;
-	et_racc = 0L;
-	currpos.x = currpos.y = r_disp = c_disp = mrk_offs = 0;
-	bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
-	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
-	if(defs.IniFile && FileExist(defs.IniFile)) {
-		OpenGraph(0L, defs.IniFile, 0L, false);
-		}
+	et_racc = 0L;
+	currpos.x = currpos.y = r_disp = c_disp = mrk_offs = 0;
+	bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
+	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
+	if(defs.IniFile && FileExist(defs.IniFile)) {
+		OpenGraph(0L, defs.IniFile, 0L, false);
+		}
 	pos_info.currpos.x = currpos.x;		pos_info.currpos.y = currpos.y;
 	pos_info.CurrText = CurrText;
-}
-
-SpreadData::~SpreadData()
-{
-	FlushData();
-	if(Disp) delete Disp;			Disp = 0L;
-	if(m_range) free(m_range);		m_range = 0L;
+}
+
+SpreadData::~SpreadData()
+{
+	FlushData();
+	if(Disp) delete Disp;			Disp = 0L;
+	if(m_range) free(m_range);		m_range = 0L;
 	if(c_range) free(c_range);		c_range = 0L;
-	if(rlw_file) free(rlw_file);	rlw_file = 0L;
-}
-
-bool
-SpreadData::Init(int nRows, int nCols)
-{
-	int i, j;
-	RECT rc;
-
+	if(rlw_file) free(rlw_file);	rlw_file = 0L;
+}
+
+bool
+SpreadData::Init(int nRows, int nCols)
+{
+	int i, j;
+	RECT rc;
+
 	cRows = nRows;	cCols = nCols;				currpos.x = currpos.y = 0;
-	new_mark = bCopyCut = false;				if(w && m_range) HideMark(true);
-	if(!Disp) {
-		Disp = new SpreadWin(g_parent, this);
-		w = Disp->w;
-		if(w) {
-			CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
-			CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
+	new_mark = bCopyCut = false;				if(w && m_range) HideMark(true);
+	if(!Disp) {
+		Disp = new SpreadWin(g_parent, this);
+		w = Disp->w;
+		if(w) {
+			CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
+			CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
 			FirstWidth = 32;
-			w->GetSize(&rc);
-			r_disp = (rc.bottom-rc.top)/CellHeight;
-			c_disp = (rc.right-rc.left)/CellWidth+1;
-			}
-		else return false;
+			w->GetSize(&rc);
+			r_disp = (rc.bottom-rc.top)/CellHeight;
+			c_disp = (rc.right-rc.left)/CellWidth+1;
+			}
+		else return false;
 		pos_info.ssOrg.x = Disp->ssOrg.x;		pos_info.ssOrg.y = Disp->ssOrg.y;
 		pos_info.CurrText = CurrText;
-		}
-	if(etRows)FlushData();
-	etRows = (EditText ***)calloc (cRows, sizeof(EditText **));
-	if(etRows) for(i = 0; i < cRows; i++) {
-		etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
-		if(etRows[i]) for(j = 0; j < cCols; j++) {
-#ifdef _DEBUG
-			char text[20];
-			sprintf (text, "%.2f", i*10.0 + j);
-			etRows[i][j] = new EditText(this, text, i, j);
-#else
-			etRows[i][j] = new EditText(this, 0L, i, j);
-#endif
-			}
-		}
-	if (LoadFile) {
-		strcpy(TmpTxt, LoadFile);	//we will reenter by recursion !
-		free(LoadFile);
-		LoadFile = 0L;
-		Disp->Command(CMD_DROPFILE, TmpTxt, w);
-		}
-	else DoPlot(w);
-	return true;
-}
-
-bool
-SpreadData::mpos2dpos(POINT *mp, POINT *dp)
-{
-	if(mp->x < (FirstWidth+10) && mp->x > FirstWidth && Disp->ssOrg.x >0) {
-		Disp->ssOrg.x -= 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		mp->x += CellWidth;
-		}
-	if(mp->y < (w->MenuHeight + CellHeight+9) && mp->y > (w->MenuHeight + CellHeight) && Disp->ssOrg.y >0) {
-		Disp->ssOrg.y -= 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		mp->y += CellHeight;
-		}
-	if(mp->x > (Disp->currRC.right-w->MenuHeight-10) && Disp->ssOrg.x < (cCols-2)) {
-		Disp->ssOrg.x += 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		mp->x -= CellWidth;
-		}
-	if(mp->y > (Disp->currRC.bottom-10) && Disp->ssOrg.y < (cRows-5)) {
-		Disp->ssOrg.y += 1;
-		do {
-			mp->y -= CellHeight;
-		} while(mp->y > (Disp->currRC.bottom-CellHeight));
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		}
-	dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
-	dp->x = (mp->x - FirstWidth)/CellWidth + Disp->ssOrg.x;
-	if(dp->y >= cRows) dp->y = cRows-1;	
-	if(dp->x >= cCols) dp->x = cCols-1;
-	return true;
+		}
+	if(etRows)FlushData();
+	etRows = (EditText ***)calloc (cRows, sizeof(EditText **));
+	if(etRows) for(i = 0; i < cRows; i++) {
+		etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
+		if(etRows[i]) for(j = 0; j < cCols; j++) {
+#ifdef _DEBUG
+			char text[20];
+#ifdef USE_WIN_SECURE
+			sprintf_s (text, 20, "%.2f", i*10.0 + j);
+#else
+			sprintf (text, "%.2f", i*10.0 + j);
+#endif
+			etRows[i][j] = new EditText(this, text, i, j);
+#else
+			etRows[i][j] = new EditText(this, 0L, i, j);
+#endif
+			}
+		}
+	if (LoadFile) {
+		rlp_strcpy(TmpTxt, TMP_TXT_SIZE, LoadFile);	//we will reenter by recursion !
+		free(LoadFile);
+		LoadFile = 0L;
+		Disp->Command(CMD_DROPFILE, TmpTxt, w);
+		}
+	else DoPlot(w);
+	return true;
 }
 
-bool
-SpreadData::Select(POINT *p)
-{
-	if(CurrText && CurrText->isInRect(p)){
-		CurrText->Update(1, w, p);
+bool
+SpreadData::mpos2dpos(POINT *mp, POINT *dp, bool can_scroll)
+{
+	int mx;
+
+	CurrGO = 0L;
+	dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
+	dp->x = Disp->ssOrg.x;
+	for(mx = mp->x - ri->GetFirstWidth() - ri->GetWidth(dp->x); mx > 0; dp->x++, mx -= ri->GetWidth(dp->x));
+	if(can_scroll && dp->x < cCols && mp->x < (ri->GetFirstWidth()+10) && mp->x > ri->GetFirstWidth() && Disp->ssOrg.x >0) {
+		Disp->ssOrg.x -= 1;
+		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+		Disp->Command(CMD_SETSCROLL, 0L, w);
+		}
+	if(can_scroll && mp->y < (w->MenuHeight + CellHeight+9) && mp->y > (w->MenuHeight + CellHeight) && Disp->ssOrg.y >0) {
+		Disp->ssOrg.y -= 1;
+		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+		Disp->Command(CMD_SETSCROLL, 0L, w);
+		}
+	if(can_scroll && mp->x > (Disp->currRC.right-w->MenuHeight-10) && Disp->ssOrg.x < (cCols-2)) {
+		Disp->ssOrg.x += 1;
+		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+		Disp->Command(CMD_SETSCROLL, 0L, w);
+		}
+	if(can_scroll && mp->y > (Disp->currRC.bottom-10) && Disp->ssOrg.y < (cRows-5)) {
+		Disp->ssOrg.y += 1;
+		do {
+			mp->y -= CellHeight;
+		} while(mp->y > (Disp->currRC.bottom-CellHeight));
+		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+		Disp->Command(CMD_SETSCROLL, 0L, w);			CurrText = 0L;
+		}
+	if(dp->y >= cRows) dp->y = cRows-1;					if(dp->x >= cCols) dp->x = cCols-1;
+	return true;
+}
+
+bool
+SpreadData::Select(POINT *p)
+{
+	if(CurrText && CurrText->isInRect(p)){
+		CurrText->Update(1, w, p);
 		Disp->Command(CMD_CURRPOS, &currpos, w);
 		if(CurrText->isFormula() && CurrText->hasMark()) et_racc = CurrText;
-		return true;
-		}
-	mpos2dpos(p, &currpos);
-	if(currpos.y < cRows && currpos.x < cCols && currpos.y >= 0 && currpos.x >= 0) {
-		if(etRows[currpos.y][currpos.x]) {
-			if(etRows[currpos.y][currpos.x] == CurrText) CurrText->Update(1, w, p);
-			else {
-				if(CurrText) CurrText->Update(2, w, p);
-				CurrText = etRows[currpos.y][currpos.x];
-				DoPlot(w);
-				CurrText->Update(1, w, p);
-				}
+		return true;
+		}
+	mpos2dpos(p, &currpos, false);
+	if(currpos.y < cRows && currpos.x < cCols && currpos.y >= 0 && currpos.x >= 0) {
+		if(etRows[currpos.y][currpos.x]) {
+			if(etRows[currpos.y][currpos.x] == CurrText) CurrText->Update(1, w, p);
+			else {
+				if(CurrText) CurrText->Update(2, w, p);
+				CurrText = etRows[currpos.y][currpos.x];
+				DoPlot(w);
+				CurrText->Update(1, w, p);
+				}
 			Disp->Command(CMD_CURRPOS, &currpos, w);
-			return true;
-			}
-		}
-	if(CurrText) CurrText->Update(2, w, p);		CurrText = 0L;
-	return false;
-}
-
-void
-SpreadData::MarkRange(char *range, POINT *cp)
-{
-	AccRange *nr, *oldr;
-	int r, c;
-
-	oldr = nr = 0L;
-	if(m_range && range && !strcmp(m_range, range)) return;		//no change
-	if(m_range) oldr = new AccRange(m_range);
-	if(range) nr = new AccRange(range);
-	if(oldr && nr && oldr->GetFirst(&c, &r)) {
-		for( ; oldr->GetNext(&c, &r); ) {
-			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && r < cRows && c >= Disp->ssOrg.x 
-				&& c < (c_disp + Disp->ssOrg.x) && c < cCols && !nr->IsInRange(c, r) && etRows[r] && etRows[r][c]){
-				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 0 : 1);
-				}
-			}
-		}
-	if(nr && nr->GetFirst(&c, &r)) {
-		for( ; nr->GetNext(&c, &r); ) {
-			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && c >= Disp->ssOrg.x 
-				&& c < (c_disp + Disp->ssOrg.x) && r < cRows && c < cCols)
-				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
-			}
-		}
-	if(range && (m_range = (char*)realloc(m_range, strlen(range)+6)))
-		strcpy(m_range, range);
+			return true;
+			}
+		}
+	if(CurrText) CurrText->Update(2, w, p);		CurrText = 0L;
+	return false;
+}
+
+void
+SpreadData::MarkRange(char *range, POINT *cp)
+{
+	AccRange *nr, *oldr;
+	int r, c, cb;
+
+	oldr = nr = 0L;
+	if(m_range && range && !strcmp(m_range, range)) return;		//no change
+	if(m_range) oldr = new AccRange(m_range);
+	if(range) nr = new AccRange(range);
+	if(oldr && nr && oldr->GetFirst(&c, &r)) {
+		for( ; oldr->GetNext(&c, &r); ) {
+			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && r < cRows && c >= Disp->ssOrg.x 
+				&& c < (c_disp + Disp->ssOrg.x) && c < cCols && !nr->IsInRange(c, r) && etRows[r] && etRows[r][c]){
+				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 0 : 1);
+				}
+			}
+		}
+	if(nr && nr->GetFirst(&c, &r)) {
+		for( ; nr->GetNext(&c, &r); ) {
+			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && c >= Disp->ssOrg.x 
+				&& c < (c_disp + Disp->ssOrg.x) && r < cRows && c < cCols)
+				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+			}
+		}
+	if(range && (m_range = (char*)realloc(m_range, cb = ((int)strlen(range)+6)))) rlp_strcpy(m_range, cb, range);
 	else if (m_range) m_range[0] = 0;
-	if(oldr) delete(oldr);	if(nr) delete(nr);
-	new_mark = true;		Disp->MarkButtons(m_range, cp);
-}
-
-void
-SpreadData::HideMark(bool cclp)
-{
-	if(cclp && c_range && c_range != m_range){
-		free(c_range);	c_range = 0L;
-		}
-	if(m_range){
-		free(m_range);	m_range = 0L;
-		DoPlot(w);
-		}
-	if(cclp) EmptyClip();		new_mark = false;
+	if(oldr) delete(oldr);	if(nr) delete(nr);
+	new_mark = true;		Disp->MarkButtons(m_range, cp);
+}
+
+void
+SpreadData::HideMark(bool cclp)
+{
+	if(cclp && c_range && c_range != m_range){
+		free(c_range);	c_range = 0L;
+		}
+	if(m_range){
+		free(m_range);	m_range = 0L;
+		DoPlot(w);
+		}
+	if(cclp) EmptyClip();		new_mark = false;
 	Disp->MarkButtons(m_range, 0L);
-}
-
-bool
-SpreadData::WriteData(char *FileName)
-{
-	FILE *File;
-	int i, j;
+}
+
+bool
+SpreadData::WriteData(char *FileName)
+{
+	FILE *File;
+	int i, j;
 	unsigned char *buff = 0L;
 	anyResult res;
-	bool bErr = false;
-
+	bool bErr = false;
+
 	if(!cRows || !cCols || !etRows) return false;
-	if(!FileName) FileName = rlw_file;
+	if(!FileName) FileName = rlw_file;
 	if(FileName && FileName[0]) BackupFile(FileName);
-	else return false;
+	else return false;
+#ifdef USE_WIN_SECURE
+	if(fopen_s(&File, FileName, "w")) {
+#else
 	if(!(File = fopen(FileName, "w"))) {
+#endif
 		ErrorBox("An error occured during write,\n\nplease try again!");
 		return false;
-		}
-	HideMark(true);
-	i = strlen(FileName);
-	//test for xml extension
-	if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
-		MemList(&buff, FF_XML);
-		if(buff){
-			if(fprintf(File, "%s", buff) <= 0) bErr = true;
-			free(buff);					fclose(File);
-			return true;
-			}
-		return false;
-		}
-	//test for tsv extension
-	if(!strcmp(".tsv", FileName+i-4) || !strcmp(".TSV", FileName+i-4)) {
-		MemList(&buff, FF_TSV);
-		if(buff){
-			if(fprintf(File, "%s", buff) <= 0) bErr = true;
-			free(buff);					fclose(File);
-			return true;
-			}
-		return false;
+		}
+	HideMark(true);
+	i = (int)strlen(FileName);
+	//test for xml extension
+	if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
+		MemList(&buff, FF_XML);
+		if(buff){
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
+			free(buff);					fclose(File);
+			return true;
+			}
+		return false;
+		}
+	//test for tsv extension
+	if(!strcmp(".tsv", FileName+i-4) || !strcmp(".TSV", FileName+i-4)) {
+		MemList(&buff, FF_TSV);
+		if(buff){
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
+			free(buff);					fclose(File);
+			return true;
+			}
+		return false;
 		}
 	//test for rlw extension
 	if(!strcmp(".rlw", FileName+i-4) || !strcmp(".RLW", FileName+i-4)) {
 		MemList(&buff, FF_RLW);
 		if(buff){
 			if(rlw_file != FileName) {
-				if(rlw_file) free(rlw_file);		rlw_file = strdup(FileName);
+				if(rlw_file) free(rlw_file);		rlw_file = _strdup(FileName);
 				}
 			if(fprintf(File, "%s", buff) <= 0) bErr = true;
 			free(buff);					fclose(File);
@@ -1029,8 +1133,8 @@ SpreadData::WriteData(char *FileName)
 			}
 		return false;
 		}
-	//else write csv
-	for(i = 0; i < cRows; i++) {
+	//else write csv
+	for(i = 0; i < cRows; i++) {
 		for(j = 0; j < cCols; j++) {
 			if(etRows[i][j]) {
 				etRows[i][j]->GetResult(&res, false);		TranslateResult(&res);
@@ -1044,182 +1148,185 @@ SpreadData::WriteData(char *FileName)
 					break;
 					}
 				}
-			if(j < (cCols-1)) fprintf(File, ", ");
-			}
-		if(fprintf(File, "\n") <= 0) bErr = true;
-		}
-	fclose(File);
+			if(j < (cCols-1)) fprintf(File, ", ");
+			}
+		if(fprintf(File, "\n") <= 0) bErr = true;
+		}
+	fclose(File);
 	if(bErr) ErrorBox("An error occured during write,\n\nplease try again!");
-	return true;
-}
-
-bool
-SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
-{
-	int i, j, l;
-	char ItemText[20];
-	bool success;
-	POINT pt;
-
+	return true;
+}
+
+bool
+SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
+{
+	int i, j;
+	char ItemText[20];
+	bool success;
+
 	if(FileName) {		//read disk file
 		if(!Disp->Command(CMD_CAN_CLOSE, 0L, 0L))return false;
-		if(0 == strcmp(".xml", FileName+strlen(FileName)-4) ||
+		if(0 == strcmp(".xml", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".XML", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".RLW", FileName+strlen(FileName)-4) ||
-			IsXmlFile(FileName)){
+			IsXmlFile(FileName)){
 			if(ReadXML(FileName, buffer, type, 0L)){
 				if(0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
-					0 == strcmp(".RLW", FileName+strlen(FileName)-4)) {
+					0 == strcmp(".RLW", FileName+strlen(FileName)-4)) {
 					if(rlw_file)	free(rlw_file);
-					rlw_file = strdup(FileName);
+					rlw_file = _strdup(FileName);
 					}
-				return true;
-				}
-			return false;
-			}
-		if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
-			0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
-			return ReadTSV(FileName, buffer, type);
-			}
-		if(!(Cache = new ReadCache())) return false;
-		if(! Cache->Open(FileName)) {
-			delete Cache;
-			sprintf(TmpTxt, "Error open data file\n\"%s\"", FileName);
-			ErrorBox(TmpTxt);
-			return false;
-			}
-		if(!Init(1, 1)) goto ReadError;
-		}
-	else if(buffer) {	//read memory buffer
-		switch(type) {
-		case FF_TSV:
-			return ReadTSV(FileName, buffer, type);
-		case FF_XML:
-			return ReadXML(FileName, buffer, type, 0L);
-		case FF_CSV:
-			if(!(Cache = new MemCache(buffer))) return false;
-			break;
-		default:
-			ErrorBox("Read from buffer with\nunknown format failed.");
-			return false;
-			}
-		}
-	else return false;
-	i = j = 0;
-	pt.x = pt.y = 0;		//pt is a dummy argument only
-	do {
-		if((success = GetItemCSV(ItemText, sizeof(ItemText)-1)) || ItemText[0]){
-			if(j >= cCols && !AddCols(j+1)) goto ReadError;
-			if(i >= cRows && !AddRows(i+1)) goto ReadError;
-			if(etRows[i][j]) etRows[i][j]->SetText("");
-			l = strlen(ItemText);
-			if(l>1 && ItemText[0] == '"') {
-				ItemText[l-1] = 0;
-				etRows[i][j]->SetText(ItemText+1);
-				etRows[i][j]->Update(20, 0L, &pt);
-				}
-			else if(l){
-				etRows[i][j]->SetText(ItemText);
-				etRows[i][j]->Update(10, 0L, &pt);
-				}
-			j++;
-			}
-		if(!success && !Cache->IsEOF()) {i++; j = 0;}	//eol
-		}while (ItemText[0] || !Cache->IsEOF());		//eof
-
-	Cache->Close();		delete Cache;		Cache = 0L;
-	Disp->ssOrg.x = Disp->ssOrg.y = 0;
-	return true;
-
-ReadError:
-	Cache->Close();		delete Cache;		Cache = 0L;
-	return false;
-
-}
-
-bool
-SpreadData::AddCols(int nCols)
-{
-	EditText **NewRow;
-	int i, j;
-
-	if (nCols <= cCols || !etRows || !etRows[0] || !etRows[0][cCols-1]) return false;
-	for(i = 0; i < cRows; i++) {
-		if(NewRow = (EditText **)realloc(etRows[i], nCols * sizeof(EditText*))){
-			for(j = cCols; j < nCols; j++) {
-				NewRow[j] = new EditText(this, 0L, i, j);
-				}
-			etRows[i] = NewRow;
-			}
-		else return false;						//memory allocation error
-		}
-	cCols = nCols;
-	return true;
-}
-
-bool
-SpreadData::AddRows(int nRows)
-{
-	int i, j;
-	EditText ***NewRows;
-
-	if (nRows <= cRows || !etRows || !etRows[cRows-1] || !etRows[cRows-1][0] ) return false;
-	NewRows = (EditText ***)realloc(etRows, nRows * sizeof(EditText **));
-	if(NewRows) etRows = NewRows;
+				return true;
+				}
+			return false;
+			}
+		if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
+			0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
+			return ReadTSV(FileName, buffer, type);
+			}
+		if(!(Cache = new ReadCache())) return false;
+		if(! Cache->Open(FileName)) {
+			delete Cache;
+			i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error open data file\n\"");
+			i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, FileName);
+			i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "\"\n");
+			ErrorBox(TmpTxt);
+			return false;
+			}
+		if(!Init(1, 1)) goto ReadError;
+		}
+	else if(buffer) {	//read memory buffer
+		switch(type) {
+		case FF_TSV:
+			return ReadTSV(FileName, buffer, type);
+		case FF_XML:
+			return ReadXML(FileName, buffer, type, 0L);
+		case FF_CSV:
+			if(!(Cache = new MemCache(buffer))) return false;
+			break;
+		default:
+			ErrorBox("Read from buffer with\nunknown format failed.");
+			return false;
+			}
+		}
+	else return false;
+	i = j = 0;
+	do {
+		if((success = GetItemCSV(ItemText, sizeof(ItemText)-1)) || ItemText[0]){
+			if(j >= cCols && !AddCols(j+1)) goto ReadError;
+			if(i >= cRows && !AddRows(i+1)) goto ReadError;
+			if(!etRows[i][j]) goto ReadError;
+			if(ItemText[0] == '"') {
+				rmquot(ItemText);
+				etRows[i][j]->SetText(ItemText);
+				etRows[i][j]->Update(20, 0L, 0L);
+				}
+			else if(ItemText[0]){
+				etRows[i][j]->SetText(ItemText);
+				etRows[i][j]->Update(10, 0L, 0L);
+				}
+			else etRows[i][j]->SetText("");
+			j++;
+			}
+		if(!success && !Cache->IsEOF()) {i++; j = 0;}	//eol
+		}while (ItemText[0] || !Cache->IsEOF());		//eof
+	Cache->Close();		delete Cache;		Cache = 0L;
+	Disp->ssOrg.x = Disp->ssOrg.y = 0;
+	return true;
+
+ReadError:
+	Cache->Close();		delete Cache;		Cache = 0L;
+	return false;
+
+}
+
+bool
+SpreadData::AddCols(int nCols)
+{
+	EditText **NewRow;
+	int i, j;
+
+	if (nCols <= cCols || !etRows || !etRows[0] || !etRows[0][cCols-1]) return false;
+	for(i = 0; i < cRows; i++) {
+		if(NewRow = (EditText **)realloc(etRows[i], nCols * sizeof(EditText*))){
+			for(j = cCols; j < nCols; j++) {
+				NewRow[j] = new EditText(this, 0L, i, j);
+				}
+			etRows[i] = NewRow;
+			}
+		else return false;						//memory allocation error
+		}
+	cCols = nCols;
+	return true;
+}
+
+bool
+SpreadData::AddRows(int nRows)
+{
+	int i, j;
+	EditText ***NewRows;
+
+	if (nRows <= cRows || !etRows || !etRows[cRows-1] || !etRows[cRows-1][0] ) return false;
+	NewRows = (EditText ***)realloc(etRows, nRows * sizeof(EditText **));
+	if(NewRows) etRows = NewRows;
 	else return false;					//memory allocation error
-	for(i = cRows; i < nRows; i++){
-		etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
-		if(etRows[i]) {
-			for(j = 0; j < cCols; j++) etRows[i][j] = new EditText(this, 0L, i, j);
-			}
-		else {							//memory allocation error
-			cRows = i-1;
-			return false;
-			}
-		}
-	cRows = nRows;
-	return true;
-}
-
-bool
-SpreadData::ChangeSize(int nCols, int nRows, bool bUndo)
-{
-	int i, j;
-	bool RetVal = true;
+	for(i = cRows; i < nRows; i++){
+		etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
+		if(etRows[i]) {
+			for(j = 0; j < cCols; j++) etRows[i][j] = new EditText(this, 0L, i, j);
+			}
+		else {							//memory allocation error
+			cRows = i-1;
+			return false;
+			}
+		}
+	cRows = nRows;
+	return true;
+}
+
+bool
+SpreadData::ChangeSize(int nCols, int nRows, bool bUndo)
+{
+	int i, j;
+	bool RetVal = true;
 	
 	if(nCols == cCols && nRows == cRows) return true;
-	if(bUndo) Undo.DataObject(Disp, w, this, 0L, 0L);
-	if(nRows && nRows < cRows) {
-		for (i = nRows; i < cRows; i++) {
-			if(etRows[i]) for (j = 0; j < cCols; j++) {
-				if(etRows[i][j]) delete etRows[i][j];
-				etRows[i][j] = NULL;
-				}
-			free(etRows[i]);
-			etRows[i] = NULL;
-			}
-		cRows = nRows;
-		}
-	if(nCols && nCols < cCols) {
-		for (i = 0; i < cRows; i++) {
-			for (j = nCols; j < cCols; j++) {
-				if(etRows[i][j]) delete etRows[i][j];
-				etRows[i][j] = NULL;
-				}
-			}
-		cCols = nCols;
-		}
-	if(nCols > cCols) if(!AddCols(nCols))RetVal = false;
-	if(RetVal && nRows > cRows) if(!AddRows(nRows))RetVal = false;
-	if(w) {
-		sprintf(TmpTxt, "%d00", nRows);
-		w->oGetTextExtent(TmpTxt, 0, &i, &j);
-		if(i > FirstWidth) FirstWidth = i;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		}
-	return RetVal;
-}
+	if(bUndo) Undo.DataObject(Disp, w, this, 0L, 0L);
+	if(nRows && nRows < cRows) {
+		for (i = nRows; i < cRows; i++) {
+			if(etRows[i]) for (j = 0; j < cCols; j++) {
+				if(etRows[i][j]) delete etRows[i][j];
+				etRows[i][j] = NULL;
+				}
+			free(etRows[i]);
+			etRows[i] = NULL;
+			}
+		cRows = nRows;
+		}
+	if(nCols && nCols < cCols) {
+		for (i = 0; i < cRows; i++) {
+			for (j = nCols; j < cCols; j++) {
+				if(etRows[i][j]) delete etRows[i][j];
+				etRows[i][j] = NULL;
+				}
+			}
+		cCols = nCols;
+		}
+	if(nCols > cCols) if(!AddCols(nCols))RetVal = false;
+	if(RetVal && nRows > cRows) if(!AddRows(nRows))RetVal = false;
+	if(w) {
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", nRows);
+#else
+		sprintf(TmpTxt, "%d00", nRows);
+#endif
+		w->oGetTextExtent(TmpTxt, 0, &i, &j);
+		if(i > FirstWidth) FirstWidth = i;
+		Disp->Command(CMD_SETSCROLL, 0L, w);
+		}
+	return RetVal;
+}
 
 bool
 SpreadData::DeleteCols()
@@ -1284,8 +1391,8 @@ SpreadData::DeleteCols()
 				}
 			}
 		cCols -= dc;
-		MoveFormula(this, m_range, TmpTxt, -dc, 0, -1, c0+1);
-		strcpy(m_range, TmpTxt);		nc--;
+		MoveFormula(this, m_range, TmpTxt, -dc, 0, -1, c0+1);		free(m_range);
+		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nc--;
 		for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
 				MoveFormula(this, etRows[i][j]->text, TmpTxt, -dc, 0, -1, c0);
@@ -1353,8 +1460,8 @@ SpreadData::InsertCols()
 					}
 				}
 			}
-		MoveFormula(this, m_range, TmpTxt, dc, 0, -1, c0);
-		strcpy(m_range, TmpTxt);		nc--;
+		MoveFormula(this, m_range, TmpTxt, dc, 0, -1, c0);		free(m_range);
+		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nc--;
 		for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
 				MoveFormula(this, etRows[i][j]->text, TmpTxt, dc, 0, -1, c0);
@@ -1428,8 +1535,8 @@ SpreadData::DeleteRows()
 				}
 			}
 		cRows -= dr;
-		MoveFormula(this, m_range, TmpTxt, 0, -dr, r0+1, -1);
-		strcpy(m_range, TmpTxt);		nr--;
+		MoveFormula(this, m_range, TmpTxt, 0, -dr, r0+1, -1);		free(m_range);
+		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nr--;
 		for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
 				MoveFormula(this, etRows[i][j]->text, TmpTxt, 0, -dr, r0, -1);
@@ -1499,8 +1606,8 @@ SpreadData::InsertRows()
 					}
 				}
 			}
-		MoveFormula(this, m_range, TmpTxt, 0, dr, r0, -1);
-		strcpy(m_range, TmpTxt);		nr--;
+		MoveFormula(this, m_range, TmpTxt, 0, dr, r0, -1);		free(m_range);
+		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nr--;
 		for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
 				MoveFormula(this, etRows[i][j]->text, TmpTxt, 0, dr, r0, -1);
@@ -1510,40 +1617,47 @@ SpreadData::InsertRows()
 		}while(nr >= 0);
 	delete ar;
 	if(w) {
+#ifdef USE_WIN_SECURE
+		sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", cRows);
+#else
 		sprintf(TmpTxt, "%d00", cRows);
+#endif
 		w->oGetTextExtent(TmpTxt, 0, &i, &j);
 		if(i > FirstWidth) FirstWidth = i;
 		Disp->Command(CMD_SETSCROLL, 0L, w);			Disp->Command(CMD_MRK_DIRTY, 0L, w);
 		}
 	return true;
 }
-
-void
-SpreadData::DoPlot(anyOutput *o)
-{
-	RECT rc;
-	int i, j, r, c;
-	AccRange *ar;
-
-	if(!w || !Disp) return;
-	w->Erase(0x00e8e8e8L);					w->ActualSize(&rc);
+
+void
+SpreadData::DoPlot(anyOutput *o)
+{
+	RECT rc;
+	int i, j, r, c;
+	AccRange *ar;
+
+	if(!w || !Disp) return;
+	w->Erase(0x00e8e8e8L);					w->ActualSize(&rc);
 	w->SetTextSpec(&ssText);				et_racc = 0L;
-	r_disp = (rc.bottom-rc.top)/CellHeight;
-	c_disp = (rc.right-rc.left)/CellWidth+1;
-	Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
-	rc.top = w->MenuHeight;					rc.bottom = rc.top + CellHeight;
-	for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
-		rc.left = FirstWidth;				rc.right = rc.left + CellWidth;
-		rc.top += CellHeight;				rc.bottom += CellHeight;
-		for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; j++) {
-			r = i + Disp->ssOrg.y;	c = j + Disp->ssOrg.x; 
-			if(r < cRows && r >= 0 && c < cCols && c >=0 && etRows[r][c]){
+	r_disp = (rc.bottom-rc.top)/CellHeight;
+	for(c = Disp->ssOrg.x, j=rc.left, c_disp = 1; c < cCols && j <= rc.right; c++, c_disp++) {
+		j += ri->GetWidth(c);
+		}
+	Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
+	rc.top = w->MenuHeight;					rc.bottom = rc.top + CellHeight;
+	for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
+		rc.left = ri->GetFirstWidth();		rc.right = rc.left + ri->GetWidth(Disp->ssOrg.x);
+		rc.top += CellHeight;				rc.bottom += CellHeight;
+		for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; j++) {
+			r = i + Disp->ssOrg.y;	c = j + Disp->ssOrg.x; 
+			if(r < cRows && r >= 0 && c < cCols && c >=0 && etRows[r][c]){
 				etRows[r][c]->SetRec(&rc);	etRows[r][c]->Update(2, 0L, 0L);
 				etRows[r][c]->Redraw(w, false);
-				}
-			rc.left += CellWidth;			rc.right += CellWidth;
+				}
+			rc.left += ri->GetWidth(Disp->ssOrg.x+j);
+			rc.right += ri->GetWidth(Disp->ssOrg.x+j+1);
 			}
-		}
+		}
 	if(bUpdate) {
 		for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
 			for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; j++) {
@@ -1558,139 +1672,144 @@ SpreadData::DoPlot(anyOutput *o)
 			&& CurrText->col >= Disp->ssOrg.x && CurrText->col < (Disp->ssOrg.x +c_disp))
 			CurrText->Update(1, w, 0L);
 	bUpdate = false;
-	if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
-		for( ; ar->GetNext(&c, &r); ) {
+	if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
+		for( ; ar->GetNext(&c, &r); ) {
 			if(r >= Disp->ssOrg.y && r < (r_disp + Disp->ssOrg.y) && c >= Disp->ssOrg.x 
-				&& r < cRows && c < cCols
-				&& c < (c_disp + Disp->ssOrg.x) && etRows[r] && etRows[r][c])
-				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
-			}
-		delete (ar);
-		}
-	if(c_range) InitCopy(0, 0L, w);			//move animated rectangle
-	w->ActualSize(&rc);		rc.bottom += CellHeight;		w->UpdateRect(&rc, false);
+				&& r < cRows && c < cCols
+				&& c < (c_disp + Disp->ssOrg.x) && etRows[r] && etRows[r][c])
+				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+			}
+		delete (ar);
+		}
+	if(c_range) InitCopy(0, 0L, w);			//move animated rectangle
+	w->ActualSize(&rc);		rc.bottom += CellHeight;		w->UpdateRect(&rc, false);
 	if(err_msg && (!last_err || strcmp(err_msg,last_err))) {
 		ErrorBox(last_err = err_msg);
-		}
-}
-
-bool
-SpreadData::DelRange()
-{
-	AccRange *ar;
+		}
+}
+
+bool
+SpreadData::DelRange()
+{
+	AccRange *ar;
 	int r, c;
-	RECT rec;
-
+	RECT rec;
+
 	if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
-		ar->BoundRec(&rec);
+		ar->BoundRec(&rec);
 		Undo.DataObject(Disp, w, this, &rec, 0L);
-		while(ar->GetNext(&c, &r)) {
-			if(r >= 0 && r < cRows && c >= 0 && c < cCols){
-				if(etRows[r][c] && etRows[r][c]->text) etRows[r][c]->SetText("");
-				}
-			}
-		delete (ar);	HideTextCursor();
-		}
-	HideMark(false);
+		while(ar->GetNext(&c, &r)) {
+			if(r >= 0 && r < cRows && c >= 0 && c < cCols){
+				if(etRows[r][c] && etRows[r][c]->text) etRows[r][c]->SetText("");
+				}
+			}
+		delete (ar);	HideTextCursor();
+		}
+	HideMark(false);
 	if(CurrText) CurrText->Update(1, w, 0L);
 	bCopyCut = false;
-	return true;
-}
-
-bool
-SpreadData::PasteRange(int cmd, char *txt)
-{
-	AccRange *cr;
-	int i, r, c;
-	RECT mrk_range;
-
-	if(new_mark && m_range && (cr = new AccRange(m_range)) && cr->GetFirst(&c, &r)) {
-		cr->BoundRec(&mrk_range);
-		for(i = 0 ; cr->GetNext(&c, &r); i++) if(c >= 0 && c < cCols && r >= 0 && r < cRows){
-			currpos.x = c;	currpos.y = r;
-			switch(cmd){
-			case CMD_PASTE_TSV: ReadTSV(0L, (unsigned char*)txt, FF_TSV);		break;
+	return true;
+}
+
+bool
+SpreadData::PasteRange(int cmd, char *txt)
+{
+	AccRange *cr;
+	int i, r, c;
+	RECT mrk_range;
+
+	if(new_mark && m_range && (cr = new AccRange(m_range)) && cr->GetFirst(&c, &r)) {
+		cr->BoundRec(&mrk_range);
+		for(i = 0 ; cr->GetNext(&c, &r); i++) if(c >= 0 && c < cCols && r >= 0 && r < cRows){
+			currpos.x = c;	currpos.y = r;
+			switch(cmd){
+			case CMD_PASTE_TSV: ReadTSV(0L, (unsigned char*)txt, FF_TSV);		break;
 			case CMD_PASTE_SSV: ReadTSV(0L, (unsigned char*)txt, FF_SSV);		break;
-			case CMD_PASTE_XML: ReadXML(0L, (unsigned char*)txt, FF_XML, i ? UNDO_CONTINUE : 0L); break;
-			case CMD_PASTE_CSV: ReadData(0L, (unsigned char*)txt, FF_CSV);		break;
-				}
-			if((mrk_range.right - mrk_range.left) == (cp_src_rec.right - cp_src_rec.left) &&
-				(mrk_range.bottom - mrk_range.top) == (cp_src_rec.bottom - cp_src_rec.top)) break;
-			if((mrk_range.right - mrk_range.left) == 1 && (cp_src_rec.right - cp_src_rec.left) > 1) break;
-			if((mrk_range.bottom - mrk_range.top) == 1 && (cp_src_rec.bottom - cp_src_rec.top) > 1) break;
-			}
-		delete cr;		return true;
-		}
-	else switch(cmd){
-		case CMD_PASTE_TSV:
-			return ReadTSV(0L, (unsigned char*)txt, FF_TSV);
+			case CMD_PASTE_XML: ReadXML(0L, (unsigned char*)txt, FF_XML, i ? UNDO_CONTINUE : 0L); break;
+			case CMD_PASTE_CSV: ReadData(0L, (unsigned char*)txt, FF_CSV);		break;
+				}
+			if((mrk_range.right - mrk_range.left) == (cp_src_rec.right - cp_src_rec.left) &&
+				(mrk_range.bottom - mrk_range.top) == (cp_src_rec.bottom - cp_src_rec.top)) break;
+			if((mrk_range.right - mrk_range.left) == 1 && (cp_src_rec.right - cp_src_rec.left) > 1) break;
+			if((mrk_range.bottom - mrk_range.top) == 1 && (cp_src_rec.bottom - cp_src_rec.top) > 1) break;
+			}
+		delete cr;		return true;
+		}
+	else switch(cmd){
+		case CMD_PASTE_TSV:
+			return ReadTSV(0L, (unsigned char*)txt, FF_TSV);
 		case CMD_PASTE_SSV:
 			return ReadTSV(0L, (unsigned char*)txt, FF_SSV);
-		case CMD_PASTE_XML:
-			return ReadXML(0L, (unsigned char*)txt, FF_XML, 0L);
-		case CMD_PASTE_CSV:
-			return ReadData(0L, (unsigned char*)txt, FF_CSV);
-		}
-	return bCopyCut = false;
-}
-
-bool
-SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
-{
-	int r, c;
-	AccRange *ar;
-	RECT rc_band, rcCopy;
-	bool bRet = false;
+		case CMD_PASTE_XML:
+			return ReadXML(0L, (unsigned char*)txt, FF_XML, 0L);
+		case CMD_PASTE_CSV:
+			return ReadData(0L, (unsigned char*)txt, FF_CSV);
+		}
+	return bCopyCut = false;
+}
+
+bool
+SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
+{
+	int i, r, c;
+	AccRange *ar;
+	RECT rc_band, rcCopy;
+	bool bRet = false;
 
 	rcCopy.left = rcCopy.top = 0;
-	rcCopy.bottom = cRows-1;		rcCopy.right = cCols-1;
-	if(cmd) {
-		bCopyCut = (cmd == CMD_CUT);
-		new_mark = false;
-		if(m_range && m_range[0]) {
-			if(c_range) free(c_range);		c_range = strdup(m_range);
-			if(c_range && (ar = new AccRange(c_range))) {
-				ar->BoundRec(&rcCopy);
-				delete ar;			bRet = true;;
-				}
+	rcCopy.bottom = cRows-1;		rcCopy.right = cCols-1;
+	if(cmd) {
+		bCopyCut = (cmd == CMD_CUT);
+		new_mark = false;
+		if(m_range && m_range[0]) {
+			if(c_range) free(c_range);
+			c_range = (char*)memdup(m_range, (int)strlen(m_range)+1, 0);
+			if(c_range && (ar = new AccRange(c_range))) {
+				ar->BoundRec(&rcCopy);
+				delete ar;			bRet = true;;
+				}
 			}
 		else if (CurrText) {
 			if(CurrText->hasMark()) return CurrText->Command(CMD_COPY, o, 0L);
 			else {
 				if(m_range) free(m_range);	m_range=0L;
-				sprintf(TmpTxt, "%s%d:%s%d", Int2ColLabel(currpos.x, false), currpos.y+1,
-					Int2ColLabel(currpos.x, false), currpos.y+1);
-				m_range = strdup(TmpTxt);		DoPlot(o);
+#ifdef USE_WIN_SECURE
+				i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+#else
+				i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+#endif
+				m_range = (char*)malloc(i*2+2);				rlp_strcpy(m_range, i+1, TmpTxt);
+				rlp_strcpy(m_range +i, i, TmpTxt);			DoPlot(o);
 				return InitCopy(cmd, tmpl, o);
 				}
-			}
-		}
-	if(bRet || !cmd) {		//calculate animated mark
+			}
+		}
+	if(bRet || !cmd) {		//calculate animated mark
 		if(c_range && (ar = new AccRange(c_range))) {
 			ar->BoundRec(&rcCopy);			delete ar;
 			}
-		if(rcCopy.right < Disp->ssOrg.x || rcCopy.bottom < Disp->ssOrg.y) {
-			HideCopyMark();			return bRet;
-			}
-		c = rcCopy.left >= Disp->ssOrg.x ? rcCopy.left : Disp->ssOrg.x;
+		if(rcCopy.right < Disp->ssOrg.x || rcCopy.bottom < Disp->ssOrg.y) {
+			HideCopyMark();			return bRet;
+			}
+		c = rcCopy.left >= Disp->ssOrg.x ? rcCopy.left : Disp->ssOrg.x;
 		r = rcCopy.top >= Disp->ssOrg.y ? rcCopy.top : Disp->ssOrg.y;
-		while(!etRows[r] && r) r--;			while(!etRows[r][c] && c) c--;
-		if(etRows[r][c]){
-			rc_band.left = etRows[r][c]->GetX()-1;	rc_band.top = etRows[r][c]->GetY()-1;
-			}
-		else return bRet;
-		c = rcCopy.right < (Disp->ssOrg.x + c_disp) ? rcCopy.right : Disp->ssOrg.x + c_disp;
+		while(!etRows[r] && r) r--;			while(!etRows[r][c] && c) c--;
+		if(etRows[r][c]){
+			rc_band.left = etRows[r][c]->GetX()-1;	rc_band.top = etRows[r][c]->GetY()-1;
+			}
+		else return bRet;
+		c = rcCopy.right < (Disp->ssOrg.x + c_disp) ? rcCopy.right : Disp->ssOrg.x + c_disp;
 		r = rcCopy.bottom < (Disp->ssOrg.y + r_disp)? rcCopy.bottom : Disp->ssOrg.y + r_disp;
-		if(r >= cRows) r = cRows-1;			if(c >= cCols) c = cRows -1;
-		if(etRows[r][c]){
-			rc_band.right = etRows[r][c]->GetX()+CellWidth;
+		if(r >= cRows) r = cRows-1;			if(c >= cCols) c = cRows -1;
+		if(etRows[r][c]){
+			rc_band.right = etRows[r][c]->GetX()+ri->GetWidth(c);
 			rc_band.bottom = etRows[r][c]->GetY()+CellHeight;
 			if(rc_band.left >= rc_band.right) rc_band.right = rc_band.left + CellWidth;
-			if(rc_band.top >= rc_band.bottom) rc_band.bottom = rc_band.top + CellHeight;
-			ShowCopyMark(o, &rc_band, 1);
-			}
-		}
-	return bRet;
+			if(rc_band.top >= rc_band.bottom) rc_band.bottom = rc_band.top + CellHeight;
+			ShowCopyMark(o, &rc_band, 1);
+			}
+		}
+	return bRet;
 }
 
 bool
@@ -1712,84 +1831,110 @@ SpreadData::SavePos()
 	pos_info.ssOrg.x = Disp->ssOrg.x;		pos_info.ssOrg.y = Disp->ssOrg.y;
 	pos_info.CurrText = CurrText;
 	return bRet;
-}
-
-bool
-SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i;
-	static int move_cr = CMD_CURRDOWN;
-	MouseEvent *mev;
-	POINT p, cp;
-	
-	if(!o) o = w;
-	switch(cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		p.x = mev->x;				p.y = mev->y;
-		if((mev->StateFlags & 1) || mev->Action == MOUSE_LBUP) {
-			mpos2dpos(&p, &cp);
-			if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
-			}
-		switch (mev->Action) {
+}
+
+bool
+SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i;
+	static int move_cr = CMD_CURRDOWN;
+	MouseEvent *mev;
+	POINT p, cp;
+	
+	if(!o) o = w;
+	switch(cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		p.x = mev->x;				p.y = mev->y;
+		if((mev->StateFlags & 1) || mev->Action == MOUSE_LBUP || p.y < (w->MenuHeight+CellHeight)) {
+			mpos2dpos(&p, &cp, (mev->StateFlags & 1) == 1);
+			if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
+			}
+		else cp.x = cp.y = 0;
+		switch (mev->Action) {
 		case MOUSE_LBDOWN:
-			if(m_range && (mev->StateFlags & 0x18)) mrk_offs = strlen(m_range);
-			else mrk_offs = 0;
-			bActive = true;		new_mark = false;
-			if(!et_racc && CurrText && !CurrText->isInRect(&p)){
-				CurrText->Update(2, w, &p);			 CurrText = 0L;	
-				DoPlot(w);
-				}
-			if(p.x < FirstWidth) cp.x = 0;
-			if(p.y < (w->MenuHeight+CellHeight)) cp.y = 0;
+			if(m_range && (mev->StateFlags & 0x18)) mrk_offs = (int)strlen(m_range);
+			else mrk_offs = 0;
+			bActive = true;		new_mark = false;
+			if(!et_racc && CurrText && !CurrText->isInRect(&p)){
+				CurrText->Update(2, w, &p);			 CurrText = 0L;	
+				DoPlot(w);
+				}
+			if(p.x < FirstWidth) cp.x = 0;
+			if(p.y < (w->MenuHeight+CellHeight)) cp.y = 0;
 			currpos.y = currpos2.y = cp.y;
-			currpos.x = currpos2.x = cp.x;
-		case MOUSE_LBDOUBLECLICK:		case MOUSE_MOVE:
-			if(!bActive) return false;
-			if(!m_range && !CurrText && cp.y < cRows && cp.x < cCols && cp.y >= 0 && cp.x >= 0)
-				CurrText = etRows[cp.y][cp.x];
-			if(mev->Action == MOUSE_MOVE && (mev->StateFlags & 1) 
-				&& !(CurrText && CurrText->isInRect(&p))) {
-				//mark rectangular range
-				if(!et_racc && !m_range && CurrText) {
-					CurrText->Update(2, w, &p);		 CurrText = 0L;	
-					}
+			currpos.x = currpos2.x = cp.x;
+		case MOUSE_MOVE:
+			if(p.y < (w->MenuHeight+CellHeight)) {
+				if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
+				}
+			else w->MouseCursor(MC_ARROW, false);
+		case MOUSE_LBDOUBLECLICK:
+			if(!bActive) return false;
+			if(!m_range && !CurrText && cp.y < cRows && cp.x < cCols && cp.y >= 0 && cp.x >= 0)
+				CurrText = etRows[cp.y][cp.x];
+			if(mev->Action == MOUSE_MOVE && (mev->StateFlags & 1) 
+				&& !(CurrText && CurrText->isInRect(&p))) {
+				//mark rectangular range
+				if(!et_racc && !m_range && CurrText) {
+					CurrText->Update(2, w, &p);		 CurrText = 0L;	
+					}
 				if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
-						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false), 
-						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
-					}
-				else {
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
-					}
-				if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
-				return true;
-				}
-			if(mev->Action == MOUSE_LBDOUBLECLICK) bActive = false;
-			if(!(mev->StateFlags & 1)) return false;
-			if(CurrText && CurrText->isInRect(&p)) {
-				return CurrText->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
-				}
-			if(etRows[cp.y][cp.x]) 
-				return etRows[cp.y][cp.x]->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
-			return false;
-		case MOUSE_LBUP:
+#ifdef USE_WIN_SECURE
+					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
+						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
+					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE - mrk_offs-i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false), 
+						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
+#else
+					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
+						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
+					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false), 
+						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
+#endif
+					}
+				else {
+#ifdef USE_WIN_SECURE
+					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
+					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE - mrk_offs-i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+#else
+					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
+					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+#endif
+					}
+				if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
+				return true;
+				}
+			if(mev->Action == MOUSE_LBDOUBLECLICK) bActive = false;
+			if(!(mev->StateFlags & 1)) return false;
+			if(CurrText && CurrText->isInRect(&p)) {
+				return CurrText->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+				}
+			if(etRows[cp.y][cp.x]) 
+				return etRows[cp.y][cp.x]->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+			return false;
+		case MOUSE_LBUP:
 			if(bActive){
+				if(p.y < (w->MenuHeight+CellHeight)) {
+					if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
+					}
 				isRowMark = p.x < FirstWidth;
 				isColMark = p.y < (w->MenuHeight+CellHeight);
-				if(isRowMark || isColMark) {
-					if(p.x < FirstWidth) {
-						currpos.x = 0;	cp.x = cCols-1;
-						}
-					if(p.y < (w->MenuHeight+CellHeight)) {
-						currpos.y = 0;	cp.y = cRows-1;
-						}
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+				if(isRowMark || isColMark) {
+					if(p.x < FirstWidth) {
+						currpos.x = 0;	cp.x = cCols-1;
+						}
+					if(p.y < (w->MenuHeight+CellHeight)) {
+						currpos.y = 0;	cp.y = cRows-1;
+						}
+#ifdef USE_WIN_SECURE
+					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE-mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
+					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE-mrk_offs-i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+#else
+					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
+					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+#endif
 					MarkRange(TmpTxt);
-					currpos2.x = cp.x;		currpos2.y = cp.y + 1;
+					currpos2.x = cp.x;		currpos2.y = cp.y + 1;
 					}
 				else if((m_range) && !new_mark) HideMark(false);
 				if(et_racc && !et_racc->isInRect(&p)) {
@@ -1799,21 +1944,25 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 						}
 					else {
 						if(!m_range) m_range = (char*)malloc(20);
+#ifdef USE_WIN_SECURE
+						sprintf_s(m_range, 20, "%s%d%", Int2ColLabel(currpos.x, false), currpos.y+1);
+#else
 						sprintf(m_range, "%s%d%", Int2ColLabel(currpos.x, false), currpos.y+1);
+#endif
 						CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
 						free(m_range);	m_range = 0L;
 						}
-					}
-				else if(m_range) {
-					CurrText = etRows[currpos.y][currpos.x];	CurrText->Update(1, w, &p);
+					}
+				else if(m_range) {
+					CurrText = etRows[currpos.y][currpos.x];	CurrText->Update(1, w, &p);
 					DoPlot(w);
 					currpos2.x = cp.x;		currpos2.y = cp.y;
-					}
-				else return Select(&p);
-				}
-			}
-		break;
-	case CMD_PASTE_TSV:		case CMD_PASTE_XML:	case CMD_PASTE_CSV:	case CMD_PASTE_SSV:
+					}
+				else return Select(&p);
+				}
+			}
+		break;
+	case CMD_PASTE_TSV:		case CMD_PASTE_XML:	case CMD_PASTE_CSV:	case CMD_PASTE_SSV:
 		if(PasteRange(cmd, (char*)tmpl)) 
 			return Disp->Command(CMD_SETSCROLL, 0L, w);
 		return false;
@@ -1829,37 +1978,41 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 				return true;
 				}
 			}
-		return false;
-	case CMD_UNLOCK:
+		return false;
+	case CMD_UNLOCK:
 		HideMark(false);
-		currpos2.x = currpos.x;		currpos2.y = currpos.y;
-		break;
-	case CMD_ERROR:
-		err_msg = (char*)tmpl;
+		currpos2.x = currpos.x;		currpos2.y = currpos.y;
+		break;
+	case CMD_ERROR:
+		if(err_msg && err_msg[0] && tmpl && *((char*)tmpl)) {
+			if(!(strcmp((char*)tmpl, "parse error")))return false;	//parse error has lowest priority
+			}
+		if(!tmpl && err_msg && err_msg[0] && strcmp(err_msg, "parse error")) return false;
+		err_msg = (char*)tmpl;
 		break;
 	case CMD_UPDATE:
 		bUpdate = true;
 		break;
 	case CMD_SAVEPOS:
-		return SavePos();
-	case CMD_CLEAR_ERROR:
-		err_msg = last_err = 0L;
-		break;
-	case CMD_TOOLMODE:						//ESC pressed
-		HideMark(true);
+		return SavePos();
+	case CMD_CLEAR_ERROR:
+		err_msg = last_err = 0L;
+		break;
+	case CMD_TOOLMODE:						//ESC pressed
+		HideMark(true);
 		if(CurrText){
 			CurrText->Update(2, w, 0L);		CurrText->Update(1, w, 0L);
 			}
 		et_racc = 0L;						w->MouseCursor(MC_ARROW, true);
-		break;
-	case CMD_UPDHISTORY:
-		if(w) w->FileHistory();
+		break;
+	case CMD_UPDHISTORY:
+		if(w) w->FileHistory();
 		break;
 	case CMD_MRK_DIRTY:
 		move_cr = CMD_CURRDOWN;
 		err_msg = last_err = 0L;
 		if(Disp) return Disp->Command(cmd, tmpl, o);
-		return false;
+		return false;
 	case CMD_ADDCHAR:
 		if(CurrText){
 			if(currpos.y < Disp->ssOrg.y) {
@@ -1872,20 +2025,20 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			if(currpos.x < Disp->ssOrg.x) {
 				Disp->ssOrg.x = currpos.x;					Disp->Command(CMD_SETSCROLL, 0L, w);
 				}
-			else if(currpos.x > (Disp->ssOrg.x + c_disp -3)) {
+			else if(currpos.x > (Disp->ssOrg.x + c_disp -3) && (CurrText->GetRX()+ 10) > Disp->currRC.right ) {
 				Disp->ssOrg.x = currpos.x - (c_disp-3);
 				if(Disp->ssOrg.x < 0) Disp->ssOrg.x = 0;	Disp->Command(CMD_SETSCROLL, 0L, w);
 				}
 			currpos2.x = currpos.x;		currpos2.y = currpos.y;
-			i = *((int*)tmpl);
+			i = *((int*)tmpl);
 			Disp->Command(CMD_CURRPOS, &currpos, w);
-			if(i == 27) return Command(CMD_TOOLMODE, tmpl, o);
-			if(i !=3 && i != 22 && i != 24 && i != 26) HideMark(true);	//Do not hide upon ^C, ^V, ^X, ^Z
-			if(i == 13) return CurrText->Command(move_cr, w, this);
-			switch(i) {
-			case 8: return CurrText->Command(CMD_BACKSP, w, this);	//Backspace
-			default: return CurrText->AddChar(*((int*)tmpl), w, Disp);
-				}
+			if(i == 27) return Command(CMD_TOOLMODE, tmpl, o);
+			if(i !=3 && i != 22 && i != 24 && i != 26) HideMark(true);	//Do not hide upon ^C, ^V, ^X, ^Z
+			if(i == 13) return CurrText->Command(move_cr, w, this);
+			switch(i) {
+			case 8: return CurrText->Command(CMD_BACKSP, w, this);	//Backspace
+			default: return CurrText->AddChar(*((int*)tmpl), w, Disp);
+				}
 			}
 		else {
 			currpos.x = currpos2.x = Disp->ssOrg.x;			currpos.y = currpos2.y = Disp->ssOrg.y;
@@ -1950,13 +2103,13 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			MarkRange(TmpTxt);							HideTextCursor();
 			}
 		break;
-	case CMD_CURRIGHT:		case CMD_CURRDOWN:
-		move_cr = cmd;
+	case CMD_CURRIGHT:		case CMD_CURRDOWN:
+		move_cr = cmd;
 	case CMD_CURRLEFT:		case CMD_CURRUP:	case CMD_POS_FIRST:		case CMD_POS_LAST:
 		if(cmd == CMD_CURRUP && Disp->ssOrg.y && CurrText && currpos.y == Disp->ssOrg.y) {
 			Disp->ssOrg.y --;		currpos.y --;
 			DoPlot(o);
-			}
+			}
 		if(cmd == CMD_CURRLEFT && Disp->ssOrg.x && CurrText && (!CurrText->Cursor()) && (currpos.x == Disp->ssOrg.x)) {
 			Disp->ssOrg.x --;		currpos.x --;	
 			CurrText->Update(2, o, 0L);
@@ -1976,41 +2129,41 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			Disp->ssOrg.y ++;		currpos.y ++;			DoPlot(o);
 			}
 		Disp->Command(CMD_CURRPOS, &currpos, w);
-		HideMark(false);
+		HideMark(false);
 		currpos2.x = currpos.x;								currpos2.y = currpos.y;
-		if(CurrText)return CurrText->Command(cmd, w, this);
+		if(CurrText)return CurrText->Command(cmd, w, this);
 		else {
 			currpos.x = currpos2.x = Disp->ssOrg.x;			currpos.y = currpos2.y = Disp->ssOrg.y;
 			if(etRows[currpos.y] && (CurrText = etRows[currpos.y][currpos.x]))
 				CurrText->Update(1, w, &p);;
 			}
-		return false;
-	case CMD_SHTAB:
-		if(currpos.y >= cRows) currpos.y = cRows-1;
-		if(currpos.x == Disp->ssOrg.x && Disp->ssOrg.x > 0) {
-			Disp->ssOrg.x -= 1;
-			Disp->Command(CMD_SETSCROLL, 0L, w);
-			}
-		if(currpos.x > Disp->ssOrg.x && etRows[currpos.y][currpos.x]) {
-			currpos.x -=1;
-			}
-	case CMD_TAB:
-		if(currpos.y >= cRows) currpos.y = cRows-1;
-		if(cmd == CMD_TAB && currpos.x < (cCols-1) && etRows[currpos.y][currpos.x]) {
-			if((FirstWidth+(currpos.x - Disp->ssOrg.x +2)*CellWidth) > Disp->currRC.right){
-				Disp->ssOrg.x += 1;
-				Disp->Command(CMD_SETSCROLL, 0L, w);
-				}
-			currpos.x +=1;
-			}
-		if(CurrText) CurrText->Update(2, w, &p);
-		CurrText = etRows[currpos.y][currpos.x];
-		if(CurrText){
-			CurrText->Update(1, w, &p);
-			CurrText->Command(cmd == CMD_TAB ? CMD_POS_FIRST : CMD_POS_LAST, o, this);
-			}
+		return false;
+	case CMD_SHTAB:
+		if(currpos.y >= cRows) currpos.y = cRows-1;
+		if(currpos.x == Disp->ssOrg.x && Disp->ssOrg.x > 0) {
+			Disp->ssOrg.x -= 1;
+			Disp->Command(CMD_SETSCROLL, 0L, w);
+			}
+		if(currpos.x > Disp->ssOrg.x && etRows[currpos.y][currpos.x]) {
+			currpos.x -=1;
+			}
+	case CMD_TAB:
+		if(currpos.y >= cRows) currpos.y = cRows-1;
+		if(cmd == CMD_TAB && currpos.x < (cCols-1) && etRows[currpos.y][currpos.x]) {
+			if((FirstWidth+(currpos.x - Disp->ssOrg.x +2)*CellWidth) > Disp->currRC.right){
+				Disp->ssOrg.x += 1;
+				Disp->Command(CMD_SETSCROLL, 0L, w);
+				}
+			currpos.x +=1;
+			}
+		if(CurrText) CurrText->Update(2, w, &p);
+		CurrText = etRows[currpos.y][currpos.x];
+		if(CurrText){
+			CurrText->Update(1, w, &p);
+			CurrText->Command(cmd == CMD_TAB ? CMD_POS_FIRST : CMD_POS_LAST, o, this);
+			}
 		Disp->Command(CMD_CURRPOS, &currpos, w);
-		return true;
+		return true;
 	case CMD_UNDO:
 		if(w) {
 			w->MouseCursor(MC_WAIT, true);
@@ -2022,45 +2175,45 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			}
 		return true;
-	case CMD_DELETE:
-		if(m_range) DelRange();
-		else if(CurrText) return CurrText->Command(cmd, o, this);
+	case CMD_DELETE:
+		if(m_range) DelRange();
+		else if(CurrText) return CurrText->Command(cmd, o, this);
 		Disp->Command(CMD_CURRPOS, &currpos, w);
-		return true;
+		return true;
 	case CMD_QUERY_COPY:		case CMD_CUT:
-		et_racc = 0L;
-		return InitCopy(cmd, tmpl, w);
-	case CMD_GET_CELLDIMS:
-		if(tmpl) {
-			((int*)tmpl)[0] = FirstWidth;	((int*)tmpl)[1] = CellWidth;
-			((int*)tmpl)[2] = CellHeight;
-			}
-		break;
-	case CMD_SET_CELLDIMS:
-		if(tmpl) {
-			FirstWidth = ((int*)tmpl)[0];	CellWidth = ((int*)tmpl)[1];
-			CellHeight = ((int*)tmpl)[2];
-			}
+		et_racc = 0L;
+		return InitCopy(cmd, tmpl, w);
+	case CMD_GET_CELLDIMS:
+		if(tmpl) {
+			((int*)tmpl)[0] = FirstWidth;	((int*)tmpl)[1] = CellWidth;
+			((int*)tmpl)[2] = CellHeight;
+			}
+		break;
+	case CMD_SET_CELLDIMS:
+		if(tmpl) {
+			FirstWidth = ((int*)tmpl)[0];	CellWidth = ((int*)tmpl)[1];
+			CellHeight = ((int*)tmpl)[2];
+			}
 		break;
-	case CMD_TEXTSIZE:
-		if(tmpl) return Disp->Command(cmd, tmpl, o);
-		return false;
-	case CMD_COPY_TSV:
-		return MemList((unsigned char**)tmpl, FF_TSV);
-	case CMD_COPY_SYLK:
-		return MemList((unsigned char**)tmpl, FF_SYLK);
-	case CMD_COPY_XML:
+	case CMD_TEXTSIZE:
+		if(tmpl) return Disp->Command(cmd, tmpl, o);
+		return false;
+	case CMD_COPY_TSV:
+		return MemList((unsigned char**)tmpl, FF_TSV);
+	case CMD_COPY_SYLK:
+		return MemList((unsigned char**)tmpl, FF_SYLK);
+	case CMD_COPY_XML:
 		return MemList((unsigned char**)tmpl, FF_XML);
 	case CMD_DOPLOT:	case CMD_REDRAW:
 		if(CurrText) CurrText->Update(2, 0L, 0L);
 		if(etRows && etRows[currpos.y] && currpos.y < cRows && currpos.x < cCols) 
 			if(CurrText = etRows[currpos.y][currpos.x]) CurrText->Update(1,0L, 0L);
-		DoPlot(o);
-		break;
+		DoPlot(o);
+		break;
 	case CMD_FILLRANGE:
-		Undo.SetDisp(w);
+		Undo.SetDisp(w);
 		FillSsRange(this, &m_range, Disp);
-		DoPlot(o);
+		DoPlot(o);
 		Undo.SetDisp(w);
 		break;
 	case CMD_GETMARK:
@@ -2077,51 +2230,51 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		return DeleteRows();
 	case CMD_DELCOL:
 		return DeleteCols();
-	}
-	return true;
-}
-
-bool
-SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags)
-{
-	int i, row, col, tag, cpgr, spgr, ufl = 0;
-	bool bContinue, bRet = false, bUndo_done = false;
-	ReadCache *XMLcache;
-	POINT pt, mov;
+	}
+	return true;
+}
+
+bool
+SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags)
+{
+	int i, row, col, tag, cpgr, spgr, ufl = 0;
+	bool bContinue, bRet = false, bUndo_done = false;
+	ReadCache *XMLcache;
+	POINT pt, mov;
 	char TmpTxt[1024], *tmp_range;
 	unsigned char *pgr = 0L;
-	RECT rc_undo;
+	RECT rc_undo;
 
-	if(file) {
-		if(!(XMLcache = new ReadCache())) return false;
-		if(! XMLcache->Open(file)) {
-			delete XMLcache;
-			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
-			ErrorBox(TmpTxt);
-			return false;
+	if(file) {
+		if(!(XMLcache = new ReadCache())) return false;
+		if(! XMLcache->Open(file)) {
+			delete XMLcache;
+			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
+			ErrorBox(TmpTxt);
+			return false;
 			}
-		bUndo_done = true;
+		bUndo_done = true;
 		if(!Init(1, 1)) goto XMLError;
-		etRows[0][0]->SetText("");
-		}
-	else if(buffer && type == FF_XML){
-		if(!(XMLcache = new MemCache(buffer))) return false;
-		if(buffer && bCopyCut) {
-			tmp_range = m_range;	m_range = c_range;
-			c_range = 0L;			DelRange();
-			m_range = tmp_range;
-			}
-		}
-	else return false;
-	pt.x = pt.y = mov.x = mov.y = 0;
-	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
-	do {
-		row = col = 0;
-		do {
-			TmpTxt[0] = XMLcache->Getc();
-			}while(TmpTxt[0] && TmpTxt[0] != '<');
-		for(i = 1; i < 5; TmpTxt[i++] = XMLcache->Getc());
-		TmpTxt[i] = 0;
+		etRows[0][0]->SetText("");
+		}
+	else if(buffer && type == FF_XML){
+		if(!(XMLcache = new MemCache(buffer))) return false;
+		if(buffer && bCopyCut) {
+			tmp_range = m_range;	m_range = c_range;
+			c_range = 0L;			DelRange();
+			m_range = tmp_range;
+			}
+		}
+	else return false;
+	pt.x = pt.y = mov.x = mov.y = 0;
+	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
+	do {
+		row = col = 0;
+		do {
+			TmpTxt[0] = XMLcache->Getc();
+			}while(TmpTxt[0] && TmpTxt[0] != '<');
+		for(i = 1; i < 5; TmpTxt[i++] = XMLcache->Getc());
+		TmpTxt[i] = 0;
 		if(!strcmp("<cell", TmpTxt)){
 			if(!bUndo_done) {
 				rc_undo.left = currpos.x;
@@ -2132,8 +2285,8 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				bUndo_done = true;
 				}
  			tag = 1;
-			}
-		else if(!strcmp("<pos1", TmpTxt)) tag = 2;
+			}
+		else if(!strcmp("<pos1", TmpTxt)) tag = 2;
 		else if(!strcmp("<pos2", TmpTxt)) tag = 3;
 		else if(!strcmp("<RLPl", TmpTxt)) {
 			do {
@@ -2152,7 +2305,7 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				AddCols(col);		AddRows(row);
 				}
 			row = col = -1;
-			}
+			}
 		else if(!strcmp("<Grap", TmpTxt)){
 			while(XMLcache->Getc() != '[');
 			pgr = (unsigned char*)malloc(spgr = 1000);
@@ -2163,146 +2316,146 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				}while(!(pgr[cpgr-1] == '<' && pgr[cpgr-2] == 0x0a));
 			pgr[cpgr-2] = 0;
 			while(XMLcache->Getc() != 0x0a);
-			OpenGraph(Disp, 0L, pgr, false);
+			if(cpgr >20)OpenGraph(Disp, 0L, pgr, false);
 			free(pgr);			tag = 0;
 			}
-		else tag = 0;
-		if(tag) {
-			do {
-				TmpTxt[0] = XMLcache->Getc();
-				}while(TmpTxt[0] && TmpTxt[0] != '"');
-			if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
-				TmpTxt[i+1] = 0;
-				row = (int)atoi(TmpTxt);
-				}
-			do {
-				TmpTxt[0] = XMLcache->Getc();
-				}while(TmpTxt[0] && TmpTxt[0] != '"');
-			if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
-				TmpTxt[i+1] = 0;
-				col = (int)atoi(TmpTxt);
-				}
-			if(tag ==2) {
-				mov.x = col;				mov.y = row;
+		else tag = 0;
+		if(tag) {
+			do {
+				TmpTxt[0] = XMLcache->Getc();
+				}while(TmpTxt[0] && TmpTxt[0] != '"');
+			if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
+				TmpTxt[i+1] = 0;
+				row = (int)atoi(TmpTxt);
+				}
+			do {
+				TmpTxt[0] = XMLcache->Getc();
+				}while(TmpTxt[0] && TmpTxt[0] != '"');
+			if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
+				TmpTxt[i+1] = 0;
+				col = (int)atoi(TmpTxt);
+				}
+			if(tag ==2) {
+				mov.x = col;				mov.y = row;
 				cp_src_rec.left = col;		cp_src_rec.top = row;
-				ufl |= 1;
-				}
-			else if(tag ==3) {
+				ufl |= 1;
+				}
+			else if(tag ==3) {
 				cp_src_rec.right = col;		cp_src_rec.bottom = row;
-				ufl |= 2;
-				}
-			else if(row && col) do {
-				do {
-					TmpTxt[0] = XMLcache->Getc();
-					}while(TmpTxt[0] && TmpTxt[0] != '<');
-				for(i = 1; i < 6; TmpTxt[i++] = XMLcache->Getc());
-				TmpTxt[i] = 0;
-				if(bContinue =(0 == strcmp("<text>", TmpTxt))) {
-					for(i = 0; i < 1023 && ('<' != (TmpTxt[i] =XMLcache->Getc())); i++);
-					TmpTxt[i] = 0;
-					//xml indices start at 1:1 !
-					row += currpos.y-1;	col += currpos.x-1;
-					if(row >= cRows)AddRows(row+1);
-					if(col >= cCols)AddCols(col+1);
-					if(i && etRows[row] && etRows[row][col]) {
-						if(TmpTxt[0] == '=') {
-							MoveFormula(this, TmpTxt, TmpTxt, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
-							}
-						etRows[row][col]->SetText(TmpTxt);
-						etRows[row][col]->Update(20, 0L, &pt);
-						}
-					}
-				}while(!bContinue);
-			}
-		}while(!XMLcache->IsEOF());
-	bRet = true;
-XMLError:
-	XMLcache->Close();
-	delete XMLcache;
-	bCopyCut = false;
-	return bRet;
-}
-
-bool
-SpreadData::ReadTSV(char *file, unsigned char *buffer, int type)
-{
-	int i, row, col;
-	char c;
-	bool bRet = false;
-	ReadCache *TSVcache;
-	POINT pt;
-
-	if(file) {
-		if(!(TSVcache = new ReadCache())) return false;
-		if(! TSVcache->Open(file)) {
-			delete TSVcache;
-			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
-			ErrorBox(TmpTxt);
-			return false;
-			}
+				ufl |= 2;
+				}
+			else if(row && col) do {
+				do {
+					TmpTxt[0] = XMLcache->Getc();
+					}while(TmpTxt[0] && TmpTxt[0] != '<');
+				for(i = 1; i < 6; TmpTxt[i++] = XMLcache->Getc());
+				TmpTxt[i] = 0;
+				if(bContinue =(0 == strcmp("<text>", TmpTxt))) {
+					for(i = 0; i < 1023 && ('<' != (TmpTxt[i] =XMLcache->Getc())); i++);
+					TmpTxt[i] = 0;
+					//xml indices start at 1:1 !
+					row += currpos.y-1;	col += currpos.x-1;
+					if(row >= cRows)AddRows(row+1);
+					if(col >= cCols)AddCols(col+1);
+					if(i && etRows[row] && etRows[row][col]) {
+						if(TmpTxt[0] == '=') {
+							MoveFormula(this, TmpTxt, TmpTxt, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
+							}
+						etRows[row][col]->SetText(TmpTxt);
+						etRows[row][col]->Update(20, 0L, &pt);
+						}
+					}
+				}while(!bContinue);
+			}
+		}while(!XMLcache->IsEOF());
+	bRet = true;
+XMLError:
+	XMLcache->Close();
+	delete XMLcache;
+	bCopyCut = false;
+	return bRet;
+}
+
+bool
+SpreadData::ReadTSV(char *file, unsigned char *buffer, int type)
+{
+	int i, row, col;
+	char c;
+	bool bRet = false;
+	ReadCache *TSVcache;
+	POINT pt;
+
+	if(file) {
+		if(!(TSVcache = new ReadCache())) return false;
+		if(! TSVcache->Open(file)) {
+			delete TSVcache;
+			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
+			ErrorBox(TmpTxt);
+			return false;
+			}
 		if(!Init(1, 1)) goto TSVError;
-		etRows[0][0]->SetText("");
-		}
-	else if(buffer && (type == FF_TSV || type == FF_SSV)) {
-		if(!(TSVcache = new MemCache(buffer))) return false;
-		}
-	else return false;
-	row = currpos.y;	col = currpos.x;
-	pt.x = pt.y = 0;
-	do {
-		do {
-			TmpTxt[0] = TSVcache->Getc();
-			switch(TmpTxt[0]) {
-			case 0x0d:					//CR
-			case 0x0a:					//LF
-				if(col == currpos.x) break;
-				row ++;			col = currpos.x;		break;
-			case 0x09:					//tab
+		etRows[0][0]->SetText("");
+		}
+	else if(buffer && (type == FF_TSV || type == FF_SSV)) {
+		if(!(TSVcache = new MemCache(buffer))) return false;
+		}
+	else return false;
+	row = currpos.y;	col = currpos.x;
+	pt.x = pt.y = 0;
+	do {
+		do {
+			TmpTxt[0] = TSVcache->Getc();
+			switch(TmpTxt[0]) {
+			case 0x0d:					//CR
+			case 0x0a:					//LF
+				if(col == currpos.x) break;
+				row ++;			col = currpos.x;		break;
+			case 0x09:					//tab
 				col ++;			break;
 			case ' ':
-				if(type == FF_SSV) col ++;				break;
-				}
-			}while(TmpTxt[0] && TmpTxt[0] < 33);
-		for(i = 1; (TmpTxt[i] = c = TSVcache->Getc())>= (type == FF_SSV ? 33 : 32); i++)
-			if(i >= 4094) i = 4094;
-		if(TmpTxt[0] && row >= cRows)AddRows(row+1);
-		if(TmpTxt[0] && col >= cCols)AddCols(col+1);
-		TmpTxt[i] = 0;
-		if(TmpTxt[0] && etRows[row] && etRows[row][col]) {
-			etRows[row][col]->SetText(TmpTxt);
-			etRows[row][col]->Update(20, 0L, &pt);
-			switch(c) {
-			case 0x0d:					//CR
-			case 0x0a:					//LF
-				row ++;			col = currpos.x;		break;
-			case 0x09:					//tab
-				col ++;			break;
+				if(type == FF_SSV) col ++;				break;
+				}
+			}while(TmpTxt[0] && ((unsigned char)TmpTxt[0] < 33));
+		for(i = 1; ((unsigned char)(TmpTxt[i] = c = TSVcache->Getc()))>= (type == FF_SSV ? 33 : 32); i++)
+		if(i >= 4094) i = 4094;
+		if(TmpTxt[0] && row >= cRows)AddRows(row+1);
+		if(TmpTxt[0] && col >= cCols)AddCols(col+1);
+		TmpTxt[i] = 0;
+		if(TmpTxt[0] && etRows[row] && etRows[row][col]) {
+			etRows[row][col]->SetText(TmpTxt);
+			etRows[row][col]->Update(20, 0L, &pt);
+			switch(c) {
+			case 0x0d:					//CR
+			case 0x0a:					//LF
+				row ++;			col = currpos.x;		break;
+			case 0x09:					//tab
+				col ++;			break;
 			case ' ':
 				if(type == FF_SSV) col ++;				break;
-				}
-			}
-		}while(!TSVcache->IsEOF());
-	bRet = true;
-TSVError:
-	TSVcache->Close();
-	delete TSVcache;
-	return bRet;
-}
-
-bool 
-SpreadData::MemList(unsigned char **ptr, int type)
-{
+				}
+			}
+		}while(!TSVcache->IsEOF());
+	bRet = true;
+TSVError:
+	TSVcache->Close();
+	delete TSVcache;
+	return bRet;
+}
+
+bool 
+SpreadData::MemList(unsigned char **ptr, int type)
+{
 	int i, j, k, nc, nl, cb = 0; 
-	long cbd = 0, size;
-	char tmptxt[8000];
-	*ptr = (unsigned char *)malloc(size = 10000);
-	unsigned char *tmpptr;
+	long cbd = 0, size;
+	char tmptxt[8000];
+	*ptr = (unsigned char *)malloc(size = 10000);
+	unsigned char *tmpptr;
 	bool bLimit = true;
 	AccRange *ar;
 	anyResult res;
-	RECT rcCopy;
-
-	if(!(*ptr))return false;
+	RECT rcCopy;
+
+	if(!(*ptr))return false;
 	if (c_range &&  c_range[0]) {
 		ar = new AccRange(c_range);			ar->BoundRec(&rcCopy);
 		if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
@@ -2311,40 +2464,40 @@ SpreadData::MemList(unsigned char **ptr, int type)
 		ar = 0L;	rcCopy.left = rcCopy.top = 0;
 		rcCopy.right = cCols-1;				rcCopy.bottom = cRows-1;
 		}
-	if(rcCopy.left < 0) rcCopy.left = 0;	if(rcCopy.right >= cCols) rcCopy.right = cCols-1;
-	if(rcCopy.top < 0) rcCopy.top = 0;		if(rcCopy.bottom >= cRows) rcCopy.bottom = cRows-1;
+	if(rcCopy.left < 0) rcCopy.left = 0;	if(rcCopy.right >= cCols) rcCopy.right = cCols-1;
+	if(rcCopy.top < 0) rcCopy.top = 0;		if(rcCopy.bottom >= cRows) rcCopy.bottom = cRows-1;
 	if(type == FF_SYLK) cbd = sprintf((char*)*ptr, "ID;PWXL;N;E\r\n"
-		"P;Pdd/mm/yyyy\r\nP;Phh:mm:ss\r\nP;Pdd/mm/yyyy hh:mm:ss\r\n");
-	else if(type == FF_XML) {
-		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
-		"<spreadsheet-snippet rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
-		if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
-			cbd += sprintf((char*)*ptr+cbd, " <pos1 row=\"%d\" "
-				"column=\"%d\"></pos1>\n", rcCopy.top, rcCopy.left);
-			cbd += sprintf((char*)*ptr+cbd, " <pos2 row=\"%d\" "
-				"column=\"%d\"></pos2>\n", rcCopy.bottom, rcCopy.right);
-			}
-		}
-	else if(type == FF_RLW) {
+		"P;Pdd/mm/yyyy\r\nP;Phh:mm:ss\r\nP;Pdd/mm/yyyy hh:mm:ss\r\n");
+	else if(type == FF_XML) {
+		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
+		"<spreadsheet-snippet rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
+		if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
+			cbd += sprintf((char*)*ptr+cbd, " <pos1 row=\"%d\" "
+				"column=\"%d\"></pos1>\n", rcCopy.top, rcCopy.left);
+			cbd += sprintf((char*)*ptr+cbd, " <pos2 row=\"%d\" "
+				"column=\"%d\"></pos2>\n", rcCopy.bottom, rcCopy.right);
+			}
+		}
+	else if(type == FF_RLW) {
 		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n"
 		"<RLPlot-data rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
 		}
-	for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
-		for(nc = 0, j = rcCopy.left; j <= rcCopy.right; cb = 0, j++, nc++) {
-			switch (type) {
-			case FF_TSV:
-				if(nl || nc) cb = sprintf(tmptxt,"%s", nc ? "\t" : "\n");
+	for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
+		for(nc = 0, j = rcCopy.left; j <= rcCopy.right; cb = 0, j++, nc++) {
+			switch (type) {
+			case FF_TSV:
+				if(nl || nc) cb = sprintf(tmptxt,"%s", nc ? "\t" : "\n");
 				if(etRows[i] && etRows[i][j]){
 					if((ar && ar->IsInRange(j,i)) || !ar) {
 						etRows[i][j]->GetResult(&res, false);
 						TranslateResult(&res);
 						cb += sprintf(tmptxt+cb, "%s", res.text);
-						}
-					tmptxt[cb] = 0;
-					}
-				break;
-			case FF_SYLK:
-				if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)){
+						}
+					tmptxt[cb] = 0;
+					}
+				break;
+			case FF_SYLK:
+				if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)){
 					etRows[i][j]->GetResult(&res, false);
 					TranslateResult(&res);
 					switch(res.type) {
@@ -2370,38 +2523,38 @@ SpreadData::MemList(unsigned char **ptr, int type)
 						break;
 						}
 					if(bCopyCut) etRows[i][j]->SetText("");
-					}
-				break;
-			case FF_RLW:	case FF_XML:
+					}
+				break;
+			case FF_RLW:	case FF_XML:
 				if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)
-					&& etRows[i][j]->text[0]){
-					cb = sprintf(tmptxt, " <cell row=\"%d\" column=\"%d\" >\n", nl+1, nc+1);
-					cb += sprintf(tmptxt+cb, "  <text>");
-					for(k = 0; k < 7880 && (etRows[i][j]->text[k]); k++) 
-						tmptxt[cb++] = etRows[i][j]->text[k];
+					&& etRows[i][j]->text[0]){
+					cb = sprintf(tmptxt, " <cell row=\"%d\" column=\"%d\" >\n", nl+1, nc+1);
+					cb += sprintf(tmptxt+cb, "  <text>");
+					for(k = 0; k < 7880 && (etRows[i][j]->text[k]); k++) 
+						tmptxt[cb++] = etRows[i][j]->text[k];
 					cb += sprintf(tmptxt+cb, "</text>\n </cell>\n");
 					if(bCopyCut) etRows[i][j]->SetText("");
 					}
-				break;
-				}
-			if((cbd+cb+100) > size){
-				if(tmpptr = (unsigned char*)realloc(*ptr, size+10000)) {
-					*ptr = tmpptr;					size += 10000;
-					}
-				else return true;	//not all but something on clipboard
-				}
-			memcpy(*ptr+cbd, tmptxt, cb+1);
-			cbd += cb;
-			}
-		if(type == FF_SYLK) {
-			if(!bLimit) {
-				cbd += sprintf((char*)*ptr+cbd, "C;Y%d;X1;K\"long strings were"
-				" truncated to 256 characters due to limitations of the SYLK format!\"\n", i+2);
-				}
-			sprintf((char*)*ptr+cbd, "E\n");
-			}
-		else if(type == FF_TSV) sprintf((char*)*ptr+cbd,"\n");
-		}
+				break;
+				}
+			if((cbd+cb+100) > size){
+				if(tmpptr = (unsigned char*)realloc(*ptr, size+10000)) {
+					*ptr = tmpptr;					size += 10000;
+					}
+				else return true;	//not all but something on clipboard
+				}
+			memcpy(*ptr+cbd, tmptxt, cb+1);
+			cbd += cb;
+			}
+		if(type == FF_SYLK) {
+			if(!bLimit) {
+				cbd += sprintf((char*)*ptr+cbd, "C;Y%d;X1;K\"long strings were"
+				" truncated to 256 characters due to limitations of the SYLK format!\"\n", i+2);
+				}
+			sprintf((char*)*ptr+cbd, "E\n");
+			}
+		else if(type == FF_TSV) sprintf((char*)*ptr+cbd,"\n");
+		}
 	if(type == FF_XML) sprintf((char*)*ptr+cbd,"</spreadsheet-snippet>\n");
 	else if(type == FF_RLW){
 		Disp->Command(CMD_WRITE_GRAPHS, ptr, (anyOutput*)&cbd);
@@ -2413,16 +2566,16 @@ SpreadData::MemList(unsigned char **ptr, int type)
 		bCopyCut = false;
 		DoPlot(w);
 		}
-	return true;
-}
-
-void SpreadMain(bool show)
-{
-	static SpreadData *w = 0L;
-
-	if(show) {
-		if(w = new SpreadData(0L)) w->Init(50, 10);
-		do_formula(w, 0L);			//init mfcalc
-		}
-	else if (w) delete(w);
-}
+	return true;
+}
+
+void SpreadMain(bool show)
+{
+	static SpreadData *w = 0L;
+
+	if(show) {
+		if(w = new SpreadData(0L)) w->Init(50, 10);
+		do_formula(w, 0L);			//init mfcalc
+		}
+	else if (w) delete(w);
+}
diff --git a/use_gui.cpp b/use_gui.cpp
index 023f00e..30dce9a 100755
--- a/use_gui.cpp
+++ b/use_gui.cpp
@@ -112,7 +112,7 @@ ssButton::Command(int cmd, void *tmpl, anyOutput *o)
 	switch (cmd) {
 	case CMD_GETTEXT:
 		if(TextDef.text && tmpl) {
-			strcpy((char*)tmpl, TextDef.text);
+			rlp_strcpy((char*)tmpl, 10, TextDef.text);
 			return true;
 			}
 		return false;
@@ -132,9 +132,10 @@ ssButton::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		return true;
 	case CMD_SETTEXT:
-		if(TextDef.text) free(TextDef.text);
-		if(tmpl) TextDef.text = strdup((char*)tmpl);
-		else TextDef.text = 0L;
+		if(tmpl) {
+			if(! TextDef.text) TextDef.text = (char*)malloc(10*sizeof(char));
+			rlp_strcpy(TextDef.text, 10, (char*)tmpl);
+			}
 		return true;
 	case CMD_GETTEXTDEF:
 		if(!tmpl) return false;
@@ -967,7 +968,7 @@ Label::AddChar(int ci, anyOutput *o)
 		Undo.String(this, &TextDef.text, 0L);
 		Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
 		}
-	if(TextDef.text) txt1 = (char*)calloc((i = strlen(TextDef.text))+2, sizeof(char));
+	if(TextDef.text) txt1 = (char*)calloc((i = (int)strlen(TextDef.text))+2, sizeof(char));
 	else txt1 = (char*)calloc((i = 0)+2, sizeof(char));
 	if(txt1) {
 		for(j = k = 0; j< i && j < CursorPos; txt1[k++] = TextDef.text[j++]);
@@ -1005,7 +1006,64 @@ Label::CalcCursorPos(int x, int y, anyOutput *o)
 		x1 = x2;
 		}
 	if(pts[3].x < pts[2].x && x < pts[3].x) CursorPos = 0;
-	else CursorPos = strlen(TextDef.text);
+	else CursorPos = (int)strlen(TextDef.text);
+}
+
+void 
+TextFrame::ShowCursor(anyOutput *o)
+{
+	int cx, cy, w, h;
+
+	if(!o) return;
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+#ifdef _WINDOWS
+	linc = o->un2iy(TextDef.fSize*lspc);
+#else
+	linc = o->un2iy(TextDef.fSize*lspc*1.2);
+#endif
+	o->SetTextSpec(&TextDef);
+	cy = rDims.top + linc * cur_pos.y;			cx = rDims.left;
+	cx += ipad.left;							cy += ipad.top;
+	if(cur_pos.y < nlines) {
+		if(lines[cur_pos.y] && lines[cur_pos.y][0] && cur_pos.x) {
+			fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &cx, &cy);
+			if(!fmt_txt.oGetTextExtent(o, &w, &h, cur_pos.x))return;
+			}
+		else {
+			if(!o->oGetTextExtent("A", 1, &w, &h))return;	w = 0;
+			}
+		Cursor.left = cx+w;		Cursor.right = cx+w;
+		Cursor.top = cy;		Cursor.bottom = cy+linc;
+		ShowTextCursor(o, &Cursor, TextDef.ColTxt);
+		}
+}
+
+void
+TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
+{
+	int i, iy, ix, x1, x2, h;
+
+	if(!o) return;
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+	o->SetTextSpec(&TextDef);
+	iy = (y-rDims.top-ipad.top)/linc;		x1 = x2 = 0;
+	if(iy >= nlines) iy = nlines-1;			cur_pos.y = iy;
+	x2 = rDims.right - rDims.left -ipad.left - ipad.right;
+	x = x - rDims.left -ipad.left;
+	fmt_txt.SetText(0L, (char*)lines[iy], &x1, &x2);
+	for(i = 0,  ix = x1 = 0; lines[iy][i]; i++) {
+		if(i) fmt_txt.oGetTextExtent(o, &x1, &h, i);
+		x1 -= (TextDef.iSize >> 2);
+		if(i && x1 <= x2 && x1 >= x) {
+			if(i >1) fmt_txt.oGetTextExtent(o, &x1, &h, i-1);
+			else x1 = 0;
+			fmt_txt.oGetTextExtent(o, &x2, &h, i);
+			ix = (abs(x1-x)<abs(x2-x)) ? i = (i-1) : i;
+			break;
+			}
+		}
+	if(ix) cur_pos.x = ix;
+	else cur_pos.x = i;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1015,6 +1073,7 @@ Graph::ExecTool(MouseEvent *mev)
 {
 	static POINT pl = {0, 0}, pc = {0, 0};
 	static DWORD color = 0L;
+	scaleINFO scale;
 	POINT line[5];
 	GraphObj **tmpPlots, *new_go;
 	TextDEF *td;
@@ -1102,7 +1161,68 @@ Graph::ExecTool(MouseEvent *mev)
 		}
 	if(ToolMode == TM_PASTE) {
 		switch (mev->Action) {
+		case MOUSE_LBDOWN:
+			CurrGO = 0L;
+			CurrDisp->MrkMode = MRK_NONE;
+			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
+			rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+			rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+			return true;
+		case MOUSE_MOVE:
+			if(mev->StateFlags &1) {
+				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+					CurrDisp->UpdateRect(&rcUpd, false);
+				line[0].x = line[4].x = pl.x;	line[0].y = line[4].y = pl.y;
+				line[1].x = pc.x = mev->x;		line[1].y = pl.y;
+				line[2].x = mev->x;				line[2].y = pc.y = mev->y;
+				line[3].x = pl.x;				line[3].y = mev->y;
+				CurrDisp->ShowLine(line, 5, 0x00c0c0c0L);
+				memcpy(&rcUpd, &rcDim, sizeof(RECT));
+				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+				IncrementMinMaxRect(&rcUpd, 2);
+				return true;
+				}
+			break;
 		case MOUSE_LBUP:
+			if(!PasteObj) return false;
+			pc.x = mev->x;			pc.y = mev->y;
+			if((lfp = (lfPOINT*)malloc(2 * sizeof(lfPOINT)))){
+				lfp[0].fx = CurrDisp->fix2un(pl.x - CurrDisp->VPorg.fx);
+				lfp[0].fy = CurrDisp->fiy2un(pl.y - CurrDisp->VPorg.fy);
+				lfp[1].fx = CurrDisp->fix2un(pc.x - CurrDisp->VPorg.fx);
+				lfp[1].fy = CurrDisp->fiy2un(pc.y - CurrDisp->VPorg.fy);
+				if(lfp[0].fx > lfp[1].fx) {
+					x = lfp[0].fx;		lfp[0].fx = lfp[1].fx;		lfp[1].fx = x;
+					}
+				if(lfp[0].fy > lfp[1].fy) {
+					y = lfp[0].fy;		lfp[0].fy = lfp[1].fy;		lfp[1].fy = y;
+					}
+				}
+			else {
+				DeleteGO(PasteObj);			PasteObj = 0L;
+				ToolMode = TM_STANDARD;		CurrDisp->MouseCursor(MC_ARROW, false);
+				return true;
+				}
+			scale.sx.fx = lfp[0].fx;	scale.sy.fx = lfp[0].fy;	scale.sz.fx = 0.0;
+			scale.sx.fy = scale.sy.fy = scale.sz.fy = 1.0;
+			if(PasteObj->Id == GO_GRAPH) {
+				if(abs(pc.x -pl.x) > 20 && abs(pc.y -pl.y) >20) {
+					x = ((Graph*)PasteObj)->GRect.Xmax - ((Graph*)PasteObj)->GRect.Xmin;
+					y = ((Graph*)PasteObj)->GRect.Ymax - ((Graph*)PasteObj)->GRect.Ymin;
+					scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x;
+					scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
+					//preserve aspect ratio
+					scale.sx.fy = (scale.sx.fy + scale.sy.fy) /2.0;
+					scale.sy.fy = scale.sx.fy;
+					}
+				((Graph*)PasteObj)->GRect.Xmax -= ((Graph*)PasteObj)->GRect.Xmin;
+				((Graph*)PasteObj)->GRect.Ymax -= ((Graph*)PasteObj)->GRect.Ymin;
+				((Graph*)PasteObj)->GRect.Ymin = ((Graph*)PasteObj)->GRect.Xmin = 0.0;
+				PasteObj->Command(CMD_SCALE, &scale, 0L);
+				Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
+				}
+			else DeleteGO(PasteObj);
+			PasteObj = 0L;
 			ToolMode = TM_STANDARD;			CurrDisp->MouseCursor(MC_ARROW, false);
 			break;
 			}
@@ -1319,27 +1439,84 @@ Graph::ExecTool(MouseEvent *mev)
 		if(Plots[NumPlots]) i = NumPlots+1;
 		else i = NumPlots;
 		switch(mev->Action) {
-		case MOUSE_LBUP:
-			if(!(td = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
-			x = CurrDisp->fix2un(mev->x-CurrDisp->VPorg.fx);
-			y = CurrDisp->fiy2un(mev->y-CurrDisp->VPorg.fy);
-			td->ColTxt = defs.Color(COL_TEXT);		td->ColBg = defs.Color(COL_BG);
-			td->RotBL = td->RotCHAR = 0.0f;			td->fSize = defs.GetSize(SIZE_TEXT);
-			td->Align = TXA_VTOP | TXA_HLEFT;		td->Style = TXS_NORMAL;
-			td->Mode = TXM_TRANSPARENT;				td->Font = FONT_HELVETICA;
-			td->text = 0L;
+		case MOUSE_LBDOWN:
 			CurrGO = 0L;
 			CurrDisp->MrkMode = MRK_NONE;
 			Command(CMD_REDRAW, 0L, CurrDisp);
-			y -= td->fSize/2.0;
-			Undo.SetGO(this, &Plots[i], new Label(this, data, x, y, td, 0L), 0L);
-			if(Plots[i]){
-				NumPlots = i+1;
-				Plots[i]->DoPlot(CurrDisp);							//init
-				CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
-				Plots[i]->moveable = 1;
+			color = 0x00cbcbcb;
+			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
+			rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+			rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+			return true;
+		case MOUSE_MOVE:
+			if(mev->StateFlags &1) {
+				CurrDisp->MouseCursor(MC_CROSS, false);
+				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+					CurrDisp->UpdateRect(&rcUpd, false);
+				line[0].x = line[4].x = pl.x;	line[0].y = line[4].y = pl.y;
+				if((ToolMode & 0x0f)==TM_ARROW) {
+					line[1].x = pc.x = mev->x;		line[1].y = pc.y = mev->y;
+					CurrDisp->ShowLine(line, 2, color);
+					}
+				else {
+					line[1].x = pc.x = mev->x;		line[1].y = pl.y;
+					line[2].x = mev->x;				line[2].y = pc.y = mev->y;
+					line[3].x = pl.x;				line[3].y = mev->y;
+					CurrDisp->ShowLine(line, 5, color);
+					}
+				memcpy(&rcUpd, &rcDim, sizeof(RECT));
+				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+				IncrementMinMaxRect(&rcUpd, 2);
+				return true;
+				}
+			break;
+		case MOUSE_LBUP:
+			pc.x = mev->x;			pc.y = mev->y;
+			if(((abs(pc.x-pl.x) >20 && abs(pc.y-pl.y) >20)) && 
+				(lfp = (lfPOINT*)malloc(2 * sizeof(lfPOINT)))){
+				lfp[0].fx = CurrDisp->fix2un(pl.x - CurrDisp->VPorg.fx);
+				lfp[0].fy = CurrDisp->fiy2un(pl.y - CurrDisp->VPorg.fy);
+				lfp[1].fx = CurrDisp->fix2un(pc.x - CurrDisp->VPorg.fx);
+				lfp[1].fy = CurrDisp->fiy2un(pc.y - CurrDisp->VPorg.fy);
+				if(Plots[NumPlots]) i = NumPlots+1;
+				else i = NumPlots;
+				new_go = new TextFrame(this, data, &lfp[0], &lfp[1], 0L);
+				if(new_go) Undo.SetGO(this, &Plots[i], new_go, 0L);
+				if(Plots[i]){
+					NumPlots = i+1;
+					Plots[i]->DoPlot(CurrDisp);							//init
+					CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);				//edit
+					Plots[i]->moveable = 1;
+					bModified = true;
+					}
+				free(lfp);
+				CurrDisp->CheckMenu(ToolMode & 0x0f, false);
+				CurrDisp->CheckMenu(ToolMode = TM_STANDARD, true);
+				CurrDisp->MouseCursor(MC_ARROW, false);
+				}
+			else {
+				CurrDisp->MouseCursor(MC_TEXT, false);
+				if(!(td = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
+				x = CurrDisp->fix2un(mev->x-CurrDisp->VPorg.fx);
+				y = CurrDisp->fiy2un(mev->y-CurrDisp->VPorg.fy);
+				td->ColTxt = defs.Color(COL_TEXT);		td->ColBg = defs.Color(COL_BG);
+				td->RotBL = td->RotCHAR = 0.0f;			td->fSize = DefSize(SIZE_TEXT);
+				td->Align = TXA_VTOP | TXA_HLEFT;		td->Style = TXS_NORMAL;
+				td->Mode = TXM_TRANSPARENT;				td->Font = FONT_HELVETICA;
+				td->text = 0L;
+				CurrGO = 0L;
+				CurrDisp->MrkMode = MRK_NONE;
+				Command(CMD_REDRAW, 0L, CurrDisp);
+				y -= td->fSize/2.0;
+				Undo.SetGO(this, &Plots[i], new Label(this, data, x, y, td, 0L), 0L);
+				if(Plots[i]){
+					NumPlots = i+1;
+					Plots[i]->DoPlot(CurrDisp);							//init
+					CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
+					Plots[i]->moveable = 1;
+					}
+				free(td);
 				}
-			free(td);
 			return true;
 			}
 		break;
@@ -1560,10 +1737,11 @@ ObjTree::DoPlot(anyOutput *o)
 		if(list[i]) {
 			curr_obj = list[i];			n = 0;
 			if(i) while(curr_obj && curr_obj != list[0]) {
-				if(curr_obj != list[0]) n += sprintf(TmpTxt + n, " -");
+				if(curr_obj != list[0]) n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -n, " -");
 				if(curr_obj) curr_obj = curr_obj->parent; 
 				}
-			sprintf(TmpTxt + n, "%s%s", n ? " " : "", get_name(i));
+			if(n) TmpTxt[n++] = ' ';
+			n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -n, get_name(i));
 			if(list[i]->Id >= GO_PLOT && list[i]->Id < GO_GRAPH) {
 				TextDef.ColTxt = ((Plot*)list[i])->hidden ? 0x00000080L : 0x00008000L;
 				}
@@ -1615,7 +1793,7 @@ ObjTree::CreateBitmap(int *bw, int *bh, anyOutput *tmpl)
 	anyOutput *bmp = 0L;
 	int h;
 	
-	h = tmpl->un2iy(TextDef.fSize) * count;
+	h = (tmpl->un2iy(TextDef.fSize)+_SBINC) * (count+1);
 	if(h > *bh) *bh = h;
 	if(bmp = NewBitmapClass(*bw, *bh, tmpl->hres, tmpl->vres)) DoPlot(bmp);
 	return bmp;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/rlplot.git



More information about the debian-science-commits mailing list