[rlplot] 16/23: Imported Upstream version 1.4

Andreas Tille tille at debian.org
Wed Jun 29 09:50:57 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 947649abef8ff2c28f1db8f87570f972c7e1c5d7
Author: Andreas Tille <tille at debian.org>
Date:   Wed Jun 29 11:43:57 2016 +0200

    Imported Upstream version 1.4
---
 Axes.cpp                    |  189 +-
 Export.cpp                  |  813 ++---
 Fileio.cpp                  |   10 +-
 Makefile                    |   54 +-
 ODbuttons.cpp               |   19 +-
 Output.cpp                  |   28 +-
 PlotObs.cpp                 |  175 +-
 PropertyDlg.cpp             | 1113 ++++---
 QT_Spec.h => QT3_Spec.h     |  632 ++--
 QT_Spec.cpp                 | 7318 ++++++++++++++++++++++++-------------------
 QT_Spec.h                   |  666 ++--
 README                      |  111 +-
 RLPLOT.ICO                  |  Bin
 RLPlot.bmp                  |  Bin
 RLPlot.xpm                  |    0
 TheDialog.cpp               |  244 +-
 TheDialog.h                 |    5 +-
 UtilObj.cpp                 |  189 +-
 Utils.cpp                   |   53 +-
 Version.h                   |    2 +-
 WinSpec.cpp                 |  129 +-
 menu.h                      |   14 +-
 mfcalc.cpp                  | 1872 +++++++----
 mfcalc.y                    |  994 ++++--
 reports.cpp                 | 1439 ++++++++-
 rlp_math.cpp                |  320 +-
 rlplot.cpp                  |  661 ++--
 rlplot.h                    |   80 +-
 RLPLOT.RC => rlplot.rc      |    9 +-
 rlplot.spec                 |    7 +-
 rlplot.spec => rlplot.spec~ |    0
 spreadwi.cpp                |   71 +-
 use_gui.cpp                 |   83 +-
 33 files changed, 10571 insertions(+), 6729 deletions(-)

diff --git a/Axes.cpp b/Axes.cpp
index b4e13ae..7d81b99 100755
--- a/Axes.cpp
+++ b/Axes.cpp
@@ -125,23 +125,35 @@ GridLine::DoPlot(anyOutput *o)
 			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);
+		if(pts[0].x != pts[1].x || pts[0].y != pts[1].y){
+			o->oPolyline(pts, 2);
+			SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+			}
+		if(pts[2].x != pts[3].x || pts[2].y != pts[3].y){
+			o->oPolyline(pts+2, 2);
+			SetMinMaxRect(&rDims, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
+			}
 		IncrementMinMaxRect(&rDims, 3);
-		if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) o->oPolyline(pts, 2);
-		if(pts[2].x != pts[3].x || pts[2].y != pts[3].y) o->oPolyline(pts+2, 2);
 		}
 }
 
 void
 GridLine::DoMark(anyOutput *o, bool mark)
 {
-	if(cpts && mark){
-		InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
-		}
-	else if(cpts) {
-		InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
+	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+		mo = GetRectBitmap(&mrc, o);
+		if(type & DL_CIRCULAR) {
+			InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
+			}
+		else {
+			if(pts[0].x != pts[1].x || pts[0].y != pts[1].y)InvertLine(pts, 2, &LineDef, &rDims, o, mark);
+			if(pts[2].x != pts[3].x || pts[2].y != pts[3].y)InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
+			}
 		}
-
+	else RestoreRectBitmap(&mo, &mrc, o);
 }
 
 bool
@@ -175,12 +187,11 @@ GridLine::Command(int cmd, void *tmpl, anyOutput *o)
 		case MOUSE_LBUP:
 			if(IsInRect(&rDims, p1.x = mev->x, p1.y = mev->y)) {
 				if(cpts && (type & DL_CIRCULAR) && IsCloseToPL(p1, cpts, ncpts)) {
-					o->ShowMark(this, MRK_GODRAW);
+					o->ShowMark(CurrGO = this, MRK_GODRAW);
 					return true;
 					}
 				else if(!(type & DL_CIRCULAR)){
-					o->ShowMark(&rDims, MRK_INVERT);
-					CurrGO = this;
+					o->ShowMark(CurrGO = this, MRK_GODRAW);
 					return true;
 					}
 				}
@@ -225,6 +236,7 @@ GridLine3D::DoMark(anyOutput *o, bool mark)
 	POINT3D *gl;
 
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		if(ls){
 			memcpy(&mrc, &rDims, sizeof(RECT));
 			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
@@ -417,6 +429,7 @@ void
 GridRadial::DoMark(anyOutput *o, bool mark)
 {
 	if(mark) {
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
 		mo = GetRectBitmap(&mrc, o);
@@ -533,8 +546,9 @@ void
 Tick::DoMark(anyOutput *o, bool mark)
 {
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6);
+		IncrementMinMaxRect(&mrc, 6 + (parent && parent->Id == GO_AXIS) ? o->un2ix(((Axis*)parent)->axline.width):o->iLine);
 		mo = GetRectBitmap(&mrc, o);
 		InvertLine(pts, 2, defs.GetOutLine(), &rDims, o, mark);
 		}
@@ -566,17 +580,6 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 		if(name) free(name);			name = 0L;
 		if(ls) delete(ls);				ls = 0L;
 		return true;
-	case CMD_HIDE_MARK:
-		if(!tmpl || !o) return false;
-		if(tmpl == (void*)label){
-			label->DoMark(o, false);
-			return true;
-			}
-		else if(tmpl == (void*)Grid){
-			Grid->DoMark(o, false);
-			return true;
-			}
-		return false;
 	case CMD_SET_TICKSTYLE:
 		flags &= ~0x07;
 		flags |= (0x07 & *((DWORD*)tmpl));
@@ -626,6 +629,9 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Grid) Grid->Command(cmd, tmpl, o);
 		if(label) label->Command(cmd, tmpl, o);
 		return true;
+	case CMD_TEXTTHERE:
+		if(label && label->Command(cmd, tmpl, o)) return true;
+		return false;
 	case CMD_MOUSE_EVENT:
 		if((flags & AXIS_GRIDLINE) && Grid && Grid->Command(cmd, tmpl, o)) return true;
 		if(label && label->Command(cmd, tmpl, o)) return true;
@@ -1188,24 +1194,6 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 		if(axisLabel) axisLabel->Command(cmd, tmpl, o);
 		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) for(i = 0; i < NumTicks; i++) {
-			if(Ticks[i]) {
-				if(tmpl == (void*)Ticks[i]) {
-					Ticks[i]->DoMark(o, false);
-					return true;
-					}	
-				else if(Ticks[i]->Command(cmd, tmpl, o)) return true;
-				}
-			}
-		if(axisLabel && axisLabel->Id == GO_MLABEL) 
-			if(axisLabel->Command(cmd, tmpl, o)) return true;
-		return false;
 	case CMD_SET_DATAOBJ:
 		Id = GO_AXIS;
 		data = (DataObj*)tmpl;
@@ -1262,6 +1250,12 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Ticks) for(i = 0; i < NumTicks; i++)
 			if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, o)) return true;
 		return false;
+	case CMD_TEXTTHERE:
+		if(axisLabel && axisLabel->Command(cmd, tmpl, o)) return true;
+		if(Ticks) for(i = 0; i < NumTicks; i++) {
+			if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, o)) return true;
+			}
+		return false;
 	case CMD_SET_AXDEF:
 		if(axis = (AxisDEF*)tmpl) {
 			if(axis && axis->owner == (void*)this) {
@@ -1392,6 +1386,113 @@ Axis::SetTick(long idx, double val, DWORD flags, char *txt)
 }
 
 void
+Axis::mkTimeAxis()
+{
+	int nstep, mode;
+	double span, val;
+	rlp_datetime start, step;
+	static char *tick_formats[] = {"y", "Y", "W", "x", "Z.V.", "d", "H:M", "d"};
+
+	span = axis->max - axis->min;
+	memset(&step, 0, sizeof(rlp_datetime));		parse_datevalue(&start, axis->Start);
+	start.hours=start.minutes=start.doy = 0;	start.seconds = val = 0.0;
+	if(span > 60.0) start.dow = 1;
+	if(span > 24000.0) {
+		step.year = start.month = start.dom = 1;
+		nstep = 2 + (int)(span / 364.0);		mode = 0;
+		}
+	else if(span > 700.0) {
+		step.month = start.month = start.dom = 1;
+		nstep = 2 + (int)(span / 28.0);			mode = 1;
+		}
+	else if(span > 300.0) {
+		step.month = start.dom = 1;
+		nstep = 2 + (int)(span / 28.0);			mode = 2;
+		}
+	else if(span > 150.0) {
+		step.month = start.dom = 1;
+		nstep = 2 + (int)(span / 28.0);			mode = 3;
+		}
+	else if(span > 60.0) {
+		step.dom = 1;
+		nstep = 6 + (int)(span/7.0);			mode = 4;
+		}
+	else if(span > 8.0) {
+		step.dom = 1;
+		nstep = 2+(int)(span);					mode = 5;
+		}
+	else if(span > 2.0) {
+		step.hours = 6;
+		nstep = 4+(int)(span*4.0);				mode = 6;
+		}
+	else if(span > 0.5) {
+		step.hours = (span > 0.9 ? 2 : 1);
+		nstep = 4+(int)(span*24.0);				mode = 7;
+		}
+	else if(span > 0.05) {
+		step.minutes = (span > 0.3 ? (span > 0.4 ? 30 : 15) : (span <= 0.1 ? 5 : 10));
+		nstep = 100;							mode = 8;
+		}
+	else if(span > 0.005) {
+		step.minutes = 1;
+		nstep = 100;							mode = 8;
+		}
+	else return;
+	if(nstep < 50) nstep = 50;					add_date(&start, 0L);
+	if(!(Ticks = (Tick**)calloc(nstep, sizeof(Tick*))))return;
+	for(NumTicks = 0; NumTicks < nstep && val <= axis->max;	NumTicks++) {
+		val = date2value(&start);
+		switch(mode) {
+		case 0:
+			if((start.year%10) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[0]));
+			else NumTicks--;					break;
+		case 1:
+			if(start.month == 1){
+				if(span <= 6000.0 || (span <= 12000.0 && (start.year%5) == 0) || (span <= 24000.0 && (start.year%10) == 0))
+					SetTick(NumTicks, val, axis->flags, date2text(&start, 
+					(span > 3000.0 && span < 12000.0)?tick_formats[0] : tick_formats[1]));
+				else NumTicks--;
+				}
+			else if(span <= 1500.0) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, 
+				date2text(&start, tick_formats[4]));
+			else NumTicks--;					break;
+		case 2:
+			SetTick(NumTicks, val, axis->flags, date2text(&start, start.month==1 ? tick_formats[0]:tick_formats[2]));
+			break;
+		case 3:
+			SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
+			break;
+		case 4:
+			if(start.dom == 1)SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
+			else if(start.dow == 1) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[4]));
+			else NumTicks--;					break;
+		case 5:
+			if(start.dow == 1) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
+			else if(span < 30.0)SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[7]));
+			else NumTicks--;					break;
+		case 6:
+			if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
+			else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+			break;
+		case 7:
+			if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[5]));
+			else if((start.hours % 6) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[6]));
+			else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+			break;
+		case 8:
+			if(start.minutes == 0){
+				if(span <= 0.3 || (start.hours %2) == 0) SetTick(NumTicks, val, axis->flags, 
+					date2text(&start, tick_formats[6]));
+				else SetTick(NumTicks, val, axis->flags, "");
+				}
+			else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+			break;
+			}
+		add_date(&start, &step);
+		}
+}
+
+void
 Axis::CreateTicks()
 {
 	int i, n, nstep;
@@ -1401,6 +1502,7 @@ Axis::CreateTicks()
 
 	if(axis->min == -HUGE_VAL || axis->min == HUGE_VAL) return;
 	if(axis->max == -HUGE_VAL || axis->max == HUGE_VAL) return;
+	if(axis->min >= axis->max) return;
 	Command(CMD_FLUSH, 0L, 0L);
 	if((axis->flags & 0xf000) == AXIS_LOG) {	//log-axis
 		if(axis->Start > defs.min4log) tmp = log10(axis->Start);
@@ -1435,6 +1537,9 @@ Axis::CreateTicks()
 			}
 		}
 	else {										//linear axis
+		if((axis->flags & 0xf000) == AXIS_DATETIME) {
+			mkTimeAxis();		return;
+			}
 		if(atv && (nstep = atv->Count()) && (Ticks = (Tick**)calloc(nstep+1, sizeof(Tick*)))) {
 			for(NumTicks = i = n = 0; NumTicks < nstep && atv->GetItem(i, &tick_label, &fVal);	i++) {
 				SetTick(NumTicks, fVal, axis->flags, tick_label);
diff --git a/Export.cpp b/Export.cpp
index b47b8ac..461ee15 100755
--- a/Export.cpp
+++ b/Export.cpp
@@ -38,511 +38,13 @@
 
 extern char TmpTxt[];
 extern Default defs;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// export to *.wmf file (windows meta file)
-// this code is based on information from the following books
-// G. Born, 'Referenzhandbuch Dateiformate', 
-//     Addison-Wesley ISBN 3-89319-815-6
-// T. Hogan, 'Die PC-referenz f�r Programmierer',
-//     Microsoft Press: Systema Verlag GmbH ISBN 3-89390-250-3
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-typedef struct {
-	unsigned short mtType, mtHeader, mtVersion, mtSize0, mtSize1, mtNoObj;
-	unsigned mtMaxRec;
-	unsigned short mtnoPar;
-}wmf_header;
-
-class ExportWMF:public anyOutput {
-public:
-	HatchOut *hgo;
-
-	ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags);
-	~ExportWMF();
-	bool SetLine(LineDEF *lDef);
-	bool SetFill(FillDEF *fill);
-	bool SetTextSpec(TextDEF *set);
-	bool StartPage();
-	bool EndPage();
-	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
-	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSolidLine(POINT *p);
-	bool oTextOut(int x, int y, char *txt, int cb);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-
-private:
-	int oFile;
-	unsigned file_size, rec_size;
-	wmf_header header;
-	unsigned short currGDIobj, maxGDIobj;
-	unsigned short hPen, hBrush, hFont;
-	GraphObj *go;
-	char *name;
-
-	unsigned short wmfCreateSolidBrush(DWORD color);
-	unsigned short wmfCreateFontIndirect(short, short, short, short, short, unsigned char,
-		unsigned char, unsigned char, unsigned char, unsigned char, unsigned char,
-		unsigned char, unsigned char, char *);
-	unsigned short wmfCreateSolidPen(DWORD color, unsigned short width);
-	void wmfDeleteObject(unsigned short obj);
-	void wmfEllipse(unsigned short, unsigned short, unsigned short, unsigned short);
-	void wmfPolyline(POINT *pts, unsigned short cp);
-	void wmfPolygon(POINT *pts, unsigned short cp);
-	void wmfRectangle(unsigned short, unsigned short, unsigned short, unsigned short);
-	void wmfSelectObject(unsigned short o);
-	void wmfSetBkColor(DWORD col);
-	void wmfSetBkMode(unsigned m);
-	void wmfSetTextAlign(unsigned a);
-	void wmfSetTextColor(DWORD col);
-	void wmfTextOut(unsigned short, unsigned short, char *, unsigned short);
-};
-
-ExportWMF::ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags)
-{
-	currGDIobj = maxGDIobj = 0;
-	hgo =0L;
-	DeskRect.left = DeskRect.top = 0;
-	DeskRect.right = DeskRect.bottom = 0x4fffffff;
-	dFillCol = 0xffffffffL;
-	hPen = 0xffff, hBrush = 0xffff, hFont = 0xffff;
-	hres = vres = res;
-	go = g;
-	if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
-	else name = 0L;
-	oFile = 0;
-	rec_size = 28;
-	header.mtType = 1;
-	header.mtHeader = 9;
-	header.mtVersion = 0x300;
-	header.mtSize0 = 1000;
-	header.mtSize1 = 0;
-	header.mtNoObj = 64;
-	header.mtMaxRec = 100;
-	header.mtnoPar = 0;
-}
-
-ExportWMF::~ExportWMF()
-{
-	if(hgo) delete hgo;
-	if(name) free(name);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//overloaded functions from the anyOutput class
-bool
-ExportWMF::SetLine(LineDEF *lDef)
-{
-	unsigned short iw;
-
-	if(hPen == 0xffff || lDef->width != LineWidth || lDef->width != LineWidth || 
-		lDef->pattern != dPattern || lDef->color != dLineCol) {
-		LineWidth = lDef->width;
-		iw = (unsigned short)(0.5 + un2fix(lDef->width));
-		dPattern = lDef->pattern;
-		RLP.finc = 256.0/((float)(un2fix(lDef->patlength*8.0)));
-		RLP.fp = 0.0;
-		if(iLine == iw && dLineCol == lDef->color && hPen != 0xffff) return true;
-		iLine = iw;
-		dLineCol = lDef->color;
-		if(hPen != 0xffff) wmfDeleteObject(hPen);
-		iw = iw > 0 ? iw : 1;
-		hPen = wmfCreateSolidPen(dLineCol, iw);
-		wmfSelectObject(hPen);
-		}
-	return true;
-}
-
-bool
-ExportWMF::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;
-		}
-	if(dFillCol != fill->color) {
-		if(hBrush != 0xffff) wmfDeleteObject(hBrush);
-		hBrush = wmfCreateSolidBrush(dFillCol = fill->color);
-		wmfSelectObject(hBrush);
-		}
-	dFillCol2 = fill->color2;
-	return true;
-}
-
-bool
-ExportWMF::SetTextSpec(TextDEF *set)
-{
-	unsigned char lfcs, lfpaf;
-	char *face;
-	bool IsModified, RetVal;
-
-	switch(set->Font){
-	case FONT_HELVETICA:
-	default:
-		lfcs = 0;
-		lfpaf = 2 | 2<<4;
-		face = "Arial";
-		break;
-	case FONT_TIMES:
-		lfcs = 0;
-		lfpaf = 2 | 1<<4;
-		face = "Times New Roman";
-		break;
-	case FONT_COURIER:
-		lfcs = 2;
-		lfpaf = 1 | 3<<4;
-		face = "Courier New";
-		break;
-		}
-	if(!set->iSize && set->fSize > 0.001f) set->iSize = un2iy(set->fSize);
-	if(!set->iSize) return false;
-	if(hFont == 0xffff || TxtSet.iSize != set->iSize || TxtSet.Style != set->Style ||
-		TxtSet.RotBL != set->RotBL || TxtSet.RotCHAR != set->RotCHAR ||
-		TxtSet.Font != set->Font || TxtSet.fSize != set->fSize) IsModified = true;
-	else IsModified = false;
-	RetVal = anyOutput::SetTextSpec(set);
-	if (IsModified && RetVal) {
-		hFont = wmfCreateFontIndirect(TxtSet.iSize, 0, 
-			iround(TxtSet.RotBL*10), iround(TxtSet.RotBL*10), 
-			(TxtSet.Style & TXS_BOLD) ? 700 : 400,
-			(TxtSet.Style & TXS_ITALIC) ? 1 : 0,
-			(TxtSet.Style & TXS_UNDERLINE) ? 1 : 0,
-			0, lfcs, 0, 0, 2, lfpaf, face);
-		}
-	if(hFont != 0xffff) wmfSelectObject(hFont);
-	return true;
-}
-
-bool 
-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;
-			}
-		}
-	else {
-		oFile = 2;		//stdout
-		}
-	VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
-	VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
-	write(oFile, &header, 18);
-	return true;
-}
-
-bool
-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);
-	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);
-	return true;
-}
-
-bool
-ExportWMF::oCircle(int x1, int y1, int x2, int y2, char* nam)
-{
-	wmfEllipse(x1, y1, x2, y2);
-	if(hgo) return hgo->oCircle(x1, y1, x2, y2);
-	return true;
-}
-
-bool
-ExportWMF::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 wmfPolyline(pts, cp);
-	return true;
-}
-
-bool
-ExportWMF::oRectangle(int x1, int y1, int x2, int y2, char *nam)
-{
-	wmfRectangle(x1, y1, x2, y2);
-	if(hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
-	return true;
-}
-
-bool
-ExportWMF::oSolidLine(POINT *p)
-{
-	wmfPolyline(p, 2);
-	return true;
-}
-
-bool
-ExportWMF::oTextOut(int x, int y, char *txt, int cb)
-{
-	if(!txt || !txt[0]) return false;
-	if(hFont != 0xffff) wmfSelectObject(hFont);
-	wmfSetTextColor(TxtSet.ColTxt);
-	wmfSetBkColor(TxtSet.ColBg);
-	wmfSetTextAlign(((TxtSet.Align & TXA_HRIGHT) ? 2 : (TxtSet.Align &
-		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, 
-		(unsigned short)((cb > 0) ? cb : strlen(txt)));
-	return true;
-}
-
-bool
-ExportWMF::oPolygon(POINT *pts, int cp, char *nam)
-{
-	wmfPolygon(pts, cp);
-	if(hgo) return hgo->oPolygon(pts, cp);
-	return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//templates for wmf file records
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-	unsigned short Value;
-}wmfObjShort;
-
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-}wmfObjCol;
-
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-	unsigned short Style;
-	DWORD Col;
-	unsigned short Hatch;
-}wmfLogBrush;
-
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-	short lfh, lfw, lfesc, lfori, lfwei;
-	unsigned char lfita, lfund, lfsto, lfcse, lfopre, lfclp, lfqua, lfpaqu;
-	char face[32];
-}wmfLogFont;
-
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-	unsigned short Style;
-	unsigned Width;
-	DWORD col;
-}wmfLogPen;
-
-typedef struct{
-	unsigned Size;
-	unsigned short Id;
-	unsigned short x1, y1, x2, y2;
-}wmfRect;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//the following routines resemble the corresponding GDI calls
-unsigned short
-ExportWMF::wmfCreateSolidBrush(DWORD color)
-{
-	wmfLogBrush lb = {7, 0x2fc, 0, color, 0};
-
-	write(oFile, &lb, 14);
-	currGDIobj++;
-	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
-	return currGDIobj-1;
-}
-
-unsigned short
-ExportWMF::wmfCreateFontIndirect(short lfHeight, short lfWidth, short lfEscapement,
-	short lfOrientation, short lfWeight, unsigned char lfItalic, unsigned char lfUnderline,
-	unsigned char lfStrikeOut, unsigned char lfCharSet, unsigned char lfOutPrecision, 
-	unsigned char lfClipPrecision, unsigned char lfQuality, unsigned char lfPitchAndFamily,
-	char *FaceName)
-{
-	wmfLogFont lf = {28, 0x2fb, lfHeight, lfWidth, lfEscapement, lfOrientation, lfWeight,
-		lfItalic, lfUnderline, lfStrikeOut, lfCharSet, lfOutPrecision, lfClipPrecision,
-		lfQuality, lfPitchAndFamily, "Arial"};
-
-	if(FaceName && FaceName[0]) rlp_strcpy(lf.face, 32, FaceName);
-	write(oFile, &lf, 56);
-	currGDIobj++;
-	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
-	return currGDIobj-1;
-}
-
-unsigned short
-ExportWMF::wmfCreateSolidPen(DWORD color, unsigned short width)
-{
-	wmfLogPen lp = {8, 0x2fa, 0, width, color};
-
-	write(oFile, &lp, 16);
-	currGDIobj++;
-	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
-	return currGDIobj-1;
-}
-
-void
-ExportWMF::wmfDeleteObject(unsigned short obj)
-{
-	wmfObjShort wo = {4, 0x1f0, obj};
-
-	if(currGDIobj == obj+1) {
-//		write(oFile, &wo, 8);
-//		currGDIobj--;
-		}
-}
-
-void
-ExportWMF::wmfEllipse(unsigned short ix1, unsigned short iy1, unsigned short ix2, unsigned short iy2)
-{
-	wmfRect rc = {7, 0x418, iy2, ix2, iy1, ix1};
-	
-	write(oFile, &rc, 14);
-}
-
-void
-ExportWMF::wmfPolyline(POINT *pts, unsigned short cp)
-{
-	wmfObjShort pl = {4+cp*2, 0x325, cp};
-	unsigned short v[2];
-	int i;
-
-	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);
-		}
-	if(pl.Size > rec_size) rec_size = pl.Size;
-}
-
-void
-ExportWMF::wmfPolygon(POINT *pts, unsigned short cp)
-{
-	wmfObjShort pl = {4+cp*2, 0x324, cp};
-	unsigned short v[2];
-	int i;
-
-	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);
-		}
-	if(pl.Size > rec_size) rec_size = pl.Size;
-}
-
-void
-ExportWMF::wmfRectangle(unsigned short ix1, unsigned short iy1, unsigned short ix2, unsigned short iy2)
-{
-	wmfRect rc = {7, 0x41B, iy2, ix2, iy1, ix1};
-	
-	write(oFile, &rc, 14);
-}
-
-void
-ExportWMF::wmfSelectObject(unsigned short o)
-{
-	wmfObjShort so  = {4, 0x12D, o};
-
-	write(oFile, &so, 8);
-}
-
-void
-ExportWMF::wmfSetBkColor(DWORD col)
-{
-	wmfObjCol co = {5, 0x201};
-
-	write(oFile, &co, 6);
-	write(oFile, &col, 4);
-}
-
-void
-ExportWMF::wmfSetBkMode(unsigned m)
-{
-	wmfObjShort mo = {5, 0x102, m & 0xffff};
-	unsigned short p;
-
-	write(oFile, &mo, 8);
-	p = m>>16;
-	write(oFile, &p, 2);
-}
-
-//cmSetMapMode()
-//cmSetPolyFillMode()
-
-void
-ExportWMF::wmfSetTextAlign(unsigned a)
-{
-	wmfObjShort ao = {5, 0x12E, a & 0xffff};
-	unsigned short p;
-
-	write(oFile, &ao, 8);
-	p = a>>16;
-	write(oFile, &p, 2);
-}
-
-void
-ExportWMF::wmfSetTextColor(DWORD col)
-{
-	wmfObjCol tc = {5, 0x209};
-
-	write(oFile, &tc, 6);
-	write(oFile, &col, 4);
-}
-
-//cmSetWindowExt()
-//cmSetWindowOrg()
-
-void
-ExportWMF::wmfTextOut(unsigned short ix1, unsigned short iy1, char *txt, unsigned short cb)
-{
-	wmfObjShort to  = {6, 0x521, cb};
-	unsigned short le, v[2] = {iy1, ix1};
-
-	le = cb &1 ? cb+1 : cb;
-	to.Size += le>>1;
-	write(oFile, &to, 8);
-	write(oFile, txt, le);
-	write(oFile, &v, 4);	
-	if(to.Size > rec_size) rec_size = to.Size;
-}
+static char *str_ind = "                              ";
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Entry point to export graph to Windows Meta File
 void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags)
 {
-	ExportWMF *ex;
-	
-
-	InfoBox("The export of Windos metafile (*.wmf) is deprecated.\n\nThis feature will be removed in future\nversions of RLPlot!\n\n");
-	ex = new ExportWMF(g, FileName, res, flags);
-	if(ex->StartPage()) {
-		g->DoPlot(ex);
-		ex->EndPage();
-		}
-	delete(ex);
+	InfoBox("The export of Windos metafile (*.wmf)\n has been dicontinued.\n\n");
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -573,11 +75,11 @@ public:
 	bool oPolygon(POINT *pts, int cp, char * nam = 0L);
 
 private:
-	int iLineWidth, cb_out;
+	int iLineWidth, cb_out, out_pos, out_size, cb_ind;
+	char *out_buff;
 	bool bUseGroupLine, bOutputPending;
 	GraphObj *go;
-	char *name, indent[80], output[120], tHatchStyle[80];
-	FILE *oFile;
+	char *name, output[120], tHatchStyle[80];
 	DWORD flags;
 
 	bool com_TextOut(int x, int y, char *txt, int cb);
@@ -596,9 +98,8 @@ ExportSVG::ExportSVG(GraphObj *g, char *FileName, DWORD flg)
 	go = g;
 	if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 	else name = 0L;
-	oFile = 0L;
-	flags = flg;
-	rlp_strcpy(indent, 80, "   ");
+	out_buff = 0L;		out_pos = out_size = 0;
+	flags = flg;		cb_ind = 3;
 	rlp_strcpy(tHatchStyle, 80, "style=\"stroke:black; stroke-width:1\"");
 	bUseGroupLine = false;
 }
@@ -671,40 +172,46 @@ ExportSVG::StartPage()
 	w = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
 	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;
-			}
-		}
-	else oFile = stdout;
-	if(flags & 0x01) fprintf(oFile, "Content-Type: image/svg+xml\n\n");
+	if(flags & 0x01) add_to_buff(&out_buff, &out_pos, &out_size, "Content-Type: image/svg+xml\n\n", 0);
 	VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
 	VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
-	fprintf(oFile, "<?xml version=\"1.0\"?>\n"
+	add_to_buff(&out_buff, &out_pos, &out_size, "<?xml version=\"1.0\"?>\n"
 		"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20001102//EN\"\n"
-		"   \"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd\">\n");
-	fprintf(oFile, "<svg %s width=\"%d\" height=\"%d\" style=\"stroke-linecap:round\">\n", 
-		defs.svgAttr ? defs.svgAttr : "", w, h);
+		"   \"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd\">\n<svg ", 0);
+	if(defs.svgAttr) add_to_buff(&out_buff, &out_pos, &out_size, defs.svgAttr, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, " width=\"", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, w, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, h, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke-linecap:round\">\n", 0);
 	if(defs.svgScript) {
-		fprintf(oFile, "<defs>\n<script type=\"text/ecmascript\"><![CDATA[\n");
-		fprintf(oFile, "\n%s\n", defs.svgScript);
-		fprintf(oFile, "\n]]></script>\n</defs>\n\n");
+		add_to_buff(&out_buff, &out_pos, &out_size, "<defs>\n<script type=\"text/ecmascript\"><![CDATA[\n\n", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, defs.svgScript, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\n\n]]></script>\n</defs>\n\n", 0);
 		}
-	fprintf(oFile, "<g transform=\"scale(0.1)\" style=\"font-family:Helvetica\">\n");
+	add_to_buff(&out_buff, &out_pos, &out_size, "<g transform=\"scale(0.1)\" style=\"font-family:Helvetica\">\n", 0);
 	return true;
 }
 
 bool
 ExportSVG::EndPage()
 {
-	fprintf(oFile, "</g>\n</svg>\n");
-	fclose (oFile);
+	FILE *oFile;
+
+	add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n</svg>\n", 0);
+	if(name && out_buff && out_pos > 20) {
+#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;
+			}
+		fprintf(oFile, "%s", out_buff);
+		free(out_buff);		fclose (oFile);
+		}
 	return true;
 }
 
@@ -715,27 +222,53 @@ ExportSVG::oCircle(int x1, int y1, int x2, int y2, char* nam)
 	if(y1 > y2) Swap(y1, y2);
 
 	if(hgo){
-		fprintf(oFile, "%s<g>  <!-- %s with pattern -->\n", indent, 
-			(x2-x1) == (y2-y1) ? "circle" : "ellipse");
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g>  <!-- ", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"circle" : (char*)"ellipse", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, " with pattern -->\n", 0);
 		Indent(true);
 		}
-	fprintf(oFile, "%s<%s%s%s%s cx=\"%d\" cy=\"%d\" ", indent,
-		(x2-x1) == (y2-y1) ? "circle" : "ellipse", nam? " name=\"" : "", 
-		nam ? nam : "", nam ? "\"" : "", (x1+x2)/2, (y1+y2)/2);
-	if((x2-x1) == (y2-y1)) fprintf(oFile, "r=\"%d\"", (x2-x1)/2);
-	else fprintf(oFile, "rx=\"%d\" ry=\"%d\"", (x2-x1)/2, (y2-y1)/2);
-	fprintf(oFile, " style=\"fill:%s; stroke:%s; stroke-width:%d\"/>\n",
-		ColName(dFillCol), ColName(dLineCol), iLineWidth);
+	add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+	add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"<circle" : (char*)"<ellipse", 0);
+	if(nam && nam[0]) {
+		add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\"", 0);
+		}
+	add_to_buff(&out_buff, &out_pos, &out_size, " cx=\"", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, (x1+x2)>>1, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" cy=\"", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, (y1+y2)>>1, false, 0);
+	if((x2-x1)==(y2-y1)) {
+		add_to_buff(&out_buff, &out_pos, &out_size, "\" r=\"", 0);
+		add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
+		}
+	else {
+		add_to_buff(&out_buff, &out_pos, &out_size, "\" rx=\"", 0);
+		add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\" ry=\"", 0);
+		add_int_to_buff(&out_buff, &out_pos, &out_size, (y2-y1)>>1, false, 0);
+		}
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
 	if(hgo) {
-		fprintf(oFile, "%s<g %s>  <!-- hatch -->\n", indent, tHatchStyle);
-		Indent(true);
-		bUseGroupLine = true;
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+		add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, ">  <!-- hatch -->\n", 0);
+		Indent(true);		bUseGroupLine = true;
 		hgo->oCircle(x1, y1, x2, y2);
+		Indent(false);		bUseGroupLine = false;
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
 		Indent(false);
-		bUseGroupLine = false;
-		fprintf(oFile, "%s</g>\n", indent);
-		Indent(false);
-		fprintf(oFile, "%s</g>\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
 		}
 	return true;
 }
@@ -744,32 +277,40 @@ bool
 ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
 {
 	int i, cb;
-	char tmptxt[40];
+	char tmptxt[120];
 
 	if(cp < 2) return false;
 	if (dPattern){
-		fprintf(oFile, "%s<g style=\"stroke:%s; stroke-width:%d; stroke-linecap:round\">"
-			"<!-- pattern line -->\n", indent, ColName(dLineCol), iLineWidth);
-		Indent(true);
-		bUseGroupLine = true;
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g style=\"stroke:", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+		add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-linecap:round\"><!-- pattern line -->\n", 0);
+		Indent(true);			bUseGroupLine = true;
 		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
 		Indent(false);
-		fprintf(oFile, "%s</g>\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
 		bUseGroupLine = false;
 		}
 	else {
 		if(cp == 2) return oSolidLine(pts);
 		bOutputPending = false;
-		cb_out = sprintf(output, "<polyline points=\""); 
+		cb_out = rlp_strcpy(output, 20,"<polyline points=\""); 
 		for(i = 0; i < cp; i++) {
+#ifdef USE_WIN_SECURE
+			cb = sprintf_s(tmptxt, 120, "%d %d ", pts[i].x, pts[i].y);
+#else
 			cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+#endif
 			AddToOutput(tmptxt, cb);
 			}
 		if(cb_out) output[cb_out-1] = '"';
 		if(!bUseGroupLine) {
 			cb = rlp_strcpy(tmptxt, 120, " style = \"fill:none; ");
 			AddToOutput(tmptxt, cb);
-			cb = rlp_strcpy(tmptxt, 120, "; stroke:");
+			cb = rlp_strcpy(tmptxt, 120, "stroke:");	//bug fixed by vefremov
 			cb += rlp_strcpy(tmptxt+cb, 120-cb, ColName(dLineCol));
 			cb += rlp_strcpy(tmptxt+cb, 120-cb, "; ");
 			AddToOutput(tmptxt, cb);
@@ -781,7 +322,9 @@ ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
 			AddToOutput(tmptxt, cb);
 			}
 		else AddToOutput("/>", 2);
-		fprintf(oFile, "%s%s\n", indent, output);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
 		if(bOutputPending)Indent(false);
 		}
 	return true;
@@ -793,23 +336,45 @@ ExportSVG::oRectangle(int x1, int y1, int x2, int y2, char *nam)
 	if(x1 > x2) Swap(x1, x2);
 	if(y1 > y2) Swap(y1, y2);
 	if(hgo){
-		fprintf(oFile, "%s<g>  <!-- rectangle with pattern -->\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g>  <!-- rectangle with pattern -->\n", 0);
 		Indent(true);
 		}
-	fprintf(oFile, "%s<rect%s%s%s x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "
-		"style=\"fill:%s; stroke:%s; stroke-width:%d\"/>\n",
-		indent, nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "",
-		x1, y1, x2-x1-1, y2-y1-1, ColName(dFillCol), ColName(dLineCol), iLineWidth);
+	add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+	add_to_buff(&out_buff, &out_pos, &out_size, "<rect", 5);
+	if(nam && nam[0]) {
+		add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 7);
+		add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\"", 1);
+		}
+	add_to_buff(&out_buff, &out_pos, &out_size, " x=\"", 4);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, x1, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" y=\"", 5);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, y1, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" width=\"", 9);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, x2-x1-1, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 10);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, y2-y1-1, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
 	if(hgo) {
-		fprintf(oFile, "%s<g %s>  <!-- hatch -->\n", indent, tHatchStyle);
-		Indent(true);
-		bUseGroupLine = true;
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+		add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, ">  <!-- hatch -->\n", 0);
+		Indent(true);				bUseGroupLine = true;
 		hgo->oRectangle(x1, y1, x2, y2, 0L);
+		Indent(false);				bUseGroupLine = false;
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
 		Indent(false);
-		bUseGroupLine = false;
-		fprintf(oFile, "%s</g>\n", indent);
-		Indent(false);
-		fprintf(oFile, "%s</g>\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
 		}
 	return true;
 }
@@ -817,11 +382,23 @@ ExportSVG::oRectangle(int x1, int y1, int x2, int y2, char *nam)
 bool
 ExportSVG::oSolidLine(POINT *p)
 {
-	if(bUseGroupLine) fprintf(oFile, "%s<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\"/>\n",
-		indent, p[0].x, p[0].y, p[1].x, p[1].y);
-	else fprintf(oFile, "%s<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" "
-		"style=\"stroke:%s; stroke-width:%d\"/>\n",
-		indent, p[0].x, p[0].y, p[1].x, p[1].y, ColName(dLineCol), iLineWidth);
+	if(!p) return false;
+	add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+	add_to_buff(&out_buff, &out_pos, &out_size, "<line x1=\"", 0);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].x, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" y1=\"", 6);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].y, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" x2=\"", 6);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].x, false, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\" y2=\"", 6);
+	add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].y, false, 0);
+	if(!bUseGroupLine) {
+		add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke:", 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+		add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+		}
+	add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 4);
 	return true;
 }
 
@@ -876,24 +453,26 @@ ExportSVG::com_TextOut(int x, int y, char *txt, int cb)
 #endif
 	AddToOutput(tmptxt, c);
 #ifdef USE_WIN_SECURE
-	c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
+	c = sprintf_s(tmptxt, 120, "font-size:%d; text-anchor:%s \">", h, 
 		(TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
 #else
 	c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
 		(TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
 #endif
 	AddToOutput(tmptxt, c);
-	if((strlen(indent)+strlen(txt)+cb_out) <110) cb_out += rlp_strcpy(output+cb_out, 120-cb_out, txt);
+	if((cb_ind+strlen(txt)+cb_out) <110) cb_out += rlp_strcpy(output+cb_out, 120-cb_out, txt);
 	else {
-		fprintf(oFile, "%s%s\n", indent, output);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
 		cb_out=rlp_strcpy(output, 120, txt);
 		}
-	if((strlen(indent) + cb_out) <104) 
-		fprintf(oFile, "%s%s</text>\n", indent, output);
-	else {
-		fprintf(oFile, "%s%s\n", indent, output);
-		fprintf(oFile, "</text>\n");
+	add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+	add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+	if((cb_ind + cb_out) <104) {
+		add_to_buff(&out_buff, &out_pos, &out_size, "</text>\n", 0);
 		}
+	else add_to_buff(&out_buff, &out_pos, &out_size, "\n</text>\n", 0);
 	return true;
 }
 
@@ -961,7 +540,8 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 
 	if(cp <3) return false;
 	if(hgo){
-		fprintf(oFile, "%s<g>  <!-- polygon with pattern -->\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g>  <!-- polygon with pattern -->\n", 0);
 		Indent(true);
 		}
 	bOutputPending = false;
@@ -982,32 +562,37 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 		}
 	if(cb_out) output[cb_out-1] = '"';
 #ifdef USE_WIN_SECURE
-	cb = sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
+	cb = sprintf_s(tmptxt, 40, " style=\"fill:%s; ", ColName(dFillCol));
 	AddToOutput(tmptxt, cb);
-	cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
+	cb = sprintf_s(tmptxt, 40, "stroke:%s; ", ColName(dLineCol));
 	AddToOutput(tmptxt, cb);
-	cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+	cb = sprintf_s(tmptxt, 40, "stroke-width:%d\"/>",iLineWidth);
 	AddToOutput(tmptxt, cb);
 #else
-	cb = sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
+	cb = sprintf(tmptxt, " style=\"fill:%s; ", ColName(dFillCol));
 	AddToOutput(tmptxt, cb);
 	cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
 	AddToOutput(tmptxt, cb);
 	cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
 	AddToOutput(tmptxt, cb);
 #endif
-	if(output)fprintf(oFile, "%s%s\n", indent, output);
+	add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+	add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+	add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
 	if(bOutputPending)Indent(false);
 	if(hgo) {
-		fprintf(oFile, "%s<g %s>  <!-- hatch -->\n", indent, tHatchStyle);
-		Indent(true);
-		bUseGroupLine = true;
-		hgo->oPolygon(pts, cp);
-		Indent(false);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+		add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, ">  <!-- hatch -->\n", 0);
+		Indent(true);				bUseGroupLine = true;
+		hgo->oPolygon(pts, cp);		Indent(false);
 		bUseGroupLine = false;
-		fprintf(oFile, "%s</g>\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
 		Indent(false);
-		fprintf(oFile, "%s</g>\n", indent);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
 		}
 	return true;
 }
@@ -1015,11 +600,12 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 void
 ExportSVG::Indent(bool ind)
 {
-	int i = (int)strlen(indent);
-
-	if(i > 20 && ind) return;
-	if(ind) strcat(indent, "   ");
-	else if(i>2) indent[i-3] = 0;
+	if(ind) {
+		if(cb_ind < 20) cb_ind += 3;
+		}
+	else {
+		if(cb_ind > 5) cb_ind -= 3;
+		}
 }
 
 void
@@ -1027,11 +613,13 @@ ExportSVG::AddToOutput(char *txt, int len)
 {
 	if(!txt || !txt[0]) return;
 	if(!len) len = (int)strlen(txt);
-	if((len + cb_out + strlen(indent)) < 110){
+	if((len + cb_out + cb_ind) < 110){
 		cb_out += rlp_strcpy(output+cb_out, 120, txt);
 		}
 	else {
-		fprintf(oFile, "%s%s\n", indent, output);
+		add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+		add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+		add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
 		if(!bOutputPending) Indent(true);
 		bOutputPending = true;
 		cb_out = rlp_strcpy(output, 120, txt);
@@ -1043,6 +631,7 @@ ExportSVG::ColName(DWORD col)
 {
 	static char txt1[20], txt2[20];
 	static int sw;
+	char *ret;
 
 	switch(col) {
 	case 0x00000000:			return "black";
@@ -1055,14 +644,12 @@ ExportSVG::ColName(DWORD col)
 	case 0x00ffffff:			return "white";
 		}
 	sw++;
-	if(sw & 0x01) {
-		sprintf(txt1, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
-		return txt1;
-		}
-	else {
-		sprintf(txt2, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
-		return txt2;
-		}
+#ifdef USE_WIN_SECURE
+	sprintf_s(ret = (sw & 0x01 ? txt1 : txt2), 20, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+#else
+	sprintf(ret = (sw & 0x01 ? txt1 : txt2), "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+#endif
+	return ret;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1127,7 +714,8 @@ ExportEPS::ExportEPS(GraphObj *g, char *FileName, DWORD flags)
 	DeskRect.right = DeskRect.bottom = 0x4fffffff;
 	dFillCol = 0xffffffffL;					hres = vres = 720.0f;
 	go = g;			bFontChange = false;	oFile = 0L;
-	if(FileName)name = strdup(FileName);	else name = 0L;
+	if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1,0);
+	else name = 0L;
 }
 
 ExportEPS::~ExportEPS()
@@ -1200,7 +788,11 @@ ExportEPS::StartPage()
 	BoundBox.bottom = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
 	BoundBox.right++;	BoundBox.bottom++;
 	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;
@@ -1214,7 +806,12 @@ ExportEPS::StartPage()
 		BoundBox.right, BoundBox.bottom);
 	fprintf(oFile, "%%%%Title: %s\n", name);
 	fprintf(oFile,"%%%%Creator: RLPlot version "SZ_VERSION"\n");
+#ifdef USE_WIN_SECURE
+	ctime_s(TmpTxt, 50, &ti);	TmpTxt[24] = 0;
+	fprintf(oFile,"%%%%CreationDate: %s", TmpTxt);
+#else
 	fprintf(oFile,"%%%%CreationDate: %s", ctime(&ti));
+#endif
 	fprintf(oFile, "%%%%Pages: 1\n%%%%DocumentFonts: (atend)\n");
 	fprintf(oFile, "%%%%EndComments\n"
 		"%%%%BeginProlog\n"
diff --git a/Fileio.cpp b/Fileio.cpp
index 055dd19..c224279 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -1684,8 +1684,8 @@ Arrow::FileIO(int rw)
 		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;
+		type = ARROW_LINE;		dh1 = dh2 = 0L;		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
 		return true;
 	case FILE_READ:
 		return ExecInput(Desc);
@@ -1992,7 +1992,7 @@ Label::FileIO(int rw)
 		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;
+		curr_z = 0.0;		is3D = false;
 		return true;
 	case FILE_READ:
 		return ExecInput(Desc);
@@ -3808,8 +3808,8 @@ Graph::FileIO(int rw)
 	ixax = iyax = -1;
 	switch(rw) {
 	case INIT_VARS:
-		InitVarsGO(Desc);			units = defs.cUnits = defs.dUnits;
-		OwnDisp = false;			dirty = true;
+		InitVarsGO(Desc);						units = defs.cUnits = defs.dUnits;
+		OwnDisp = bDialogOpen = 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);
diff --git a/Makefile b/Makefile
index 5c4223d..aacf7b2 100755
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Makefile, Copyright 2002-2006 R.Lackner
+# Makefile, Copyright 2002-2007 R.Lackner
 # 
 #
 #    This file is part of RLPlot.
@@ -20,27 +20,42 @@
 # This Makefile assumes that you installed Trolltechs QT in /usr/local/qt
 #   visit: http://www.trolltech.com for download and licence information
 #
-QTDIR = /usr/lib/qt3
 CC = g++
-#CFLAGS = -I$(QTDIR)/include -pipe -O2 -g
-CFLAGS = -I$(QTDIR)/include -pipe -O2
-LIBS = -L$(QTDIR)/lib -L/usr/X11R6/lib
-QTLIBS = -lqt-mt
 X11LIBS = -lX11 -lm
 SRCDIR = ./
 
+QT3DIR = /usr/lib/qt-3.3
+QT3MOC = /usr/lib/qt-3.3/bin/moc
+MOC3FLAGS =
+QT3CFLAGS = "-I$(QT3DIR)/include -pipe -O2"
+QT3H = QT3_Spec.h
+QT3LIBS = "-L$(QT3DIR)/lib -L/usr/X11R6/lib -lqt-mt"
+
+QT4DIR = /usr/lib/qt4
+QT4MOC = /usr/lib/qt4/bin/moc-qt4
+MOC4FLAGS = "MOCFLAGS=-DQT_VERSION=0x040000"
+QT4CFLAGS = "-I/usr/include/Qt -pipe -O2"
+QT4H = QT_Spec.h
+QT4LIBS = "-L$(QT4DIR)/lib -L/usr/X11R6/lib -lQtCore -lQtGui -lQtNetwork"
+
+
 GENOBJ = exprlp.o rlplot.o Output.o Utils.o UtilObj.o\
  Fileio.o Export.o PlotObs.o Axes.o mfcalc.o rlp_math.o no_gui.o
 
 OBJECTS = moc_QT_Spec.o QT_Spec.o Output.o Utils.o UtilObj.o\
  TheDialog.o rlplot.o Fileio.o PropertyDlg.o spreadwi.o\
- Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o use_gui.o\
+ Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o use_gui.o\
  reports.o
 
 all:
-	make rlplot QTDIR=$(QTDIR) 
-	make exprlp 
-	make clean
+	make Qt4
+	make exprlp
+
+Qt4:
+	make rlplot QTDIR=$(QT4DIR) MOC=$(QT4MOC) CFLAGS=$(QT4CFLAGS) QTH=$(QT4H) $(MOC4FLAGS) LIBS=$(QT4LIBS)
+
+Qt3:
+	make rlplot QTDIR=$(QT3DIR) MOC=$(QT3MOC) CFLAGS=$(QT3CFLAGS) QTH=$(QT3H) $(MOC3FLAGS) LIBS=$(QT3LIBS)
 
 rlplot: $(OBJECTS)
 	$(CC) $(LIBS) -o rlplot $(OBJECTS) $(QTLIBS) $(X11LIBS)
@@ -58,7 +73,8 @@ moc_QT_Spec.o: moc_QT_Spec.cpp $(SRCDIR)QT_Spec.h
 	$(CC) $(CFLAGS) -o $@ -c $<
 
 moc_QT_Spec.cpp: $(SRCDIR)QT_Spec.h
-	$(QTDIR)/bin/moc $(SRCDIR)QT_Spec.h -o moc_QT_Spec.cpp
+#	$(QTDIR)/bin/moc-qt4 $(SRCDIR)QT_Spec.h -o moc_QT_Spec.cpp -DQT_VERSION=0x040000
+	$(MOC) $(SRCDIR)$(QTH) -o moc_QT_Spec.cpp $(MOCFLAGS)
 
 mfcalc.o: $(SRCDIR)mfcalc.cpp
 	$(CC) $(CFLAGS) -o $@ -c $<
@@ -109,16 +125,16 @@ ODbuttons.o: $(SRCDIR)ODbuttons.cpp $(SRCDIR)rlplot.h
 	$(CC) $(CFLAGS) -o $@ -c $<
 
 Axes.o: $(SRCDIR)Axes.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $<
+	$(CC) $(CFLAGS) -o $@ -c $<
 
-no_gui.o: $(SRCDIR)no_gui.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $<
-
-use_gui.o: $(SRCDIR)use_gui.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $<
+no_gui.o: $(SRCDIR)no_gui.cpp $(SRCDIR)rlplot.h
+	$(CC) $(CFLAGS) -o $@ -c $<
 
-reports.o: $(SRCDIR)reports.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $<
+use_gui.o: $(SRCDIR)use_gui.cpp $(SRCDIR)rlplot.h
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+reports.o: $(SRCDIR)reports.cpp $(SRCDIR)rlplot.h
+	$(CC) $(CFLAGS) -o $@ -c $<
 
 
 
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index 1c81e4b..5d0f3d6 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -729,16 +729,31 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 			o->oRectangle(rec->left+29, rec->bottom-35, rec->left+33, rec->bottom-3);
 			o->oRectangle(rec->left+36, rec->top+30, rec->left+40, rec->bottom-3);
 			break;
-		case 504:
+		case 504:	case 507:
 			o->SetFill(&FillR);
 			o->oRectangle(rec->left+9, rec->top+30, rec->left+13, rec->bottom-3);
-			o->oRectangle(rec->right-20, rec->top+10, rec->right-16, rec->bottom-3);
+			o->oRectangle(rec->right-20, id == 507 ? rec->top + 25 : rec->top+10, rec->right-16, rec->bottom-3);
 			o->SetFill(&FillG);
 			o->oRectangle(rec->left+13, rec->top+25, rec->left+17, rec->bottom-3);
 			o->oRectangle(rec->right-16, rec->top+15, rec->right-12, rec->bottom-3);
 			o->SetFill(&FillB);
 			o->oRectangle(rec->left+17, rec->top+35, rec->left+21, rec->bottom-3);
 			o->oRectangle(rec->right-12, rec->top+20, rec->right-8, rec->bottom-3);
+			if(id == 507) {
+				o->SetLine(&Line);
+				pts[0].x = pts[1].x = rec->left+11;			pts[0].y = rec->top+20;
+				pts[1].y = rec->top+40;						o->oSolidLine(pts);
+				pts[0].x = pts[1].x = rec->left+15;			pts[0].y = rec->top+15;
+				pts[1].y = rec->top+35;						o->oSolidLine(pts);
+				pts[0].x = pts[1].x = rec->left+19;			pts[0].y = rec->top+30;
+				pts[1].y = rec->top+40;						o->oSolidLine(pts);
+				pts[0].x = pts[1].x = rec->right-18;		pts[0].y = rec->top+15;
+				pts[1].y = rec->top+35;						o->oSolidLine(pts);
+				pts[0].x = pts[1].x = rec->right-14;		pts[0].y = rec->top+10;
+				pts[1].y = rec->top+20;						o->oSolidLine(pts);
+				pts[0].x = pts[1].x = rec->right-10;		pts[0].y = rec->top+10;
+				pts[1].y = rec->top+30;						o->oSolidLine(pts);
+				}
 			break;
 		case 505:
 			o->SetFill(&FillY);
diff --git a/Output.cpp b/Output.cpp
index 2edb765..9749dad 100755
--- a/Output.cpp
+++ b/Output.cpp
@@ -408,17 +408,15 @@ anyOutput::ShowMark(void *src, int Mode)
 	GraphObj *go;
 
 	if(MrkMode != MRK_NONE) HideMark();
-	MrkMode = Mode;			MrkRect = src;
+	MrkMode = Mode;			MrkRect = src;		HideCopyMark();
 	switch (Mode) {
 		case MRK_INVERT:
 			return UpdateRect((RECT*)src, true);
 		case MRK_GODRAW:	case MRK_SSB_DRAW:
-			go = (GraphObj *) src;
-			go->DoMark(this, true);
+			go = (GraphObj *) src;				go->DoMark(this, true);
 			CurrGO = go;
 			if(CurrLabel && CurrLabel != CurrGO) {
-				HideTextCursor();
-				CurrLabel = 0L;
+				HideTextCursor();				CurrLabel = 0L;
 				}
 			return true;
 		}
@@ -428,7 +426,6 @@ anyOutput::ShowMark(void *src, int Mode)
 bool
 anyOutput::HideMark()
 {
-	CurrGO = 0L;
 	switch(MrkMode) {
 		case MRK_NONE:
 			return true;
@@ -437,13 +434,10 @@ anyOutput::HideMark()
 			return UpdateRect((RECT*)MrkRect, false);
 		case MRK_GODRAW:
 			MrkMode = MRK_NONE;					//inhibit reentrance
-			if(CurrGraph) {
-				if(CurrGraph->Command(CMD_HIDE_MARK, MrkRect, this)){
-					return true;
-					}
-				else CurrGraph->Command(CMD_REDRAW, 0L, this);
-				}
-			else ((GraphObj*)MrkRect)->DoMark(this, false);
+			if(CurrLabel && CurrLabel->Command(CMD_HIDEMARK, 0L, this))
+				CurrGraph->Command(CMD_REDRAW, 0L, this);
+			else if(MrkRect)((GraphObj*)MrkRect)->DoMark(this, false);
+			else if(CurrGraph) CurrGraph->Command(CMD_REDRAW, 0L, this);
 			return true;
 		case MRK_SSB_DRAW:
 			MrkMode = MRK_NONE;
@@ -520,10 +514,14 @@ anyOutput::TextCursor(char *txt, POINT p, POINT *fit, int *pos, int dx)
 	if(fit && pos) *pos = CurrPos;
 	disp.left = disp.right = w+dx;
 	disp.top = p.y;
+	if(TxtSet.Align & TXA_VCENTER) {
+		disp.top -= (TxtSet.iSize>>1);
+		}
 #ifdef _WINDOWS
-	disp.bottom = disp.top + TxtSet.iSize;
+	disp.bottom = disp.top + TxtSet.iSize-1;
 #else
-	disp.bottom = disp.top + iround(TxtSet.iSize*1.25);
+	disp.top -= 1;
+	disp.bottom = disp.top + iround(TxtSet.iSize*1.25)-2;
 #endif
 	ShowTextCursor(this, &disp, 0x0L);
 	return true;
diff --git a/PlotObs.cpp b/PlotObs.cpp
index 6119931..fb2f240 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -53,7 +53,7 @@ Plot::Plot(GraphObj *par, DataObj *d):GraphObj(par, d)
 		}
 	use_xaxis = use_yaxis = use_zaxis = 0;	hidden = 0;
 	x_info = y_info = z_info = data_desc = 0L;
-	x_tv = y_tv = 0L;
+	x_tv = y_tv = 0L;	x_dtype = y_dtype = z_dtype = 0;
 }
 
 double
@@ -276,7 +276,7 @@ PlotScatt::PlotScatt(GraphObj *par, DataObj *d, DWORD presel):Plot(par, d)
 		}
 }
 
-PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars):Plot(par, d)
+PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars, ErrorBar **errs):Plot(par, d)
 {
 	int i;
 
@@ -290,6 +290,15 @@ PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars):Plot(par,
 				}
 			}
 		}
+	if(cBars && errs) {
+		if((Errors = (ErrorBar**)calloc(cBars, sizeof(Bar*)))) {
+			nPoints = cBars;
+			for(i = 0; i < cBars; i++) {
+				if((Errors[i] = errs[i])) Errors[i]->parent = this;
+				errs[i] = 0L;
+				}
+			}
+		}
 	Id = GO_PLOTSCATT;
 }
 
@@ -476,6 +485,9 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 		return UseAxis(*((int*)tmpl));
 	case CMD_FLUSH:
 		return ForEach(FE_FLUSH, 0L, 0L);
+	case CMD_TEXTTHERE:
+		if(Labels) for(i = 0; i < nPoints; i++)	if(Labels[i] &&  Labels[i]->Command(cmd, tmpl, o))	return true;
+		return false;
 	case CMD_AUTOSCALE:
 		if(hidden) return false;
 		if(dirty){
@@ -522,7 +534,7 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 			((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
 			}
 		return true;
-	case CMD_SCALE:			case CMD_HIDE_MARK:
+	case CMD_SCALE:
 		return ForEach(cmd, tmpl, o);
 	case CMD_MUTATE:		case CMD_REPL_GO:
 		dirty = true;
@@ -582,7 +594,7 @@ PlotScatt::ForEach(int cmd, void *tmp, anyOutput *o)
 		(GraphObj**)DropLines, (GraphObj**)Labels, (GraphObj**)Bars};
 	GraphObj ***go = 0L;
 	GraphObj **tmpPlots;
-	bool bRedraw, bFound;
+	bool bRedraw;
 
 	switch(cmd) {
 	case FE_MUTATE:
@@ -681,17 +693,6 @@ PlotScatt::ForEach(int cmd, void *tmp, anyOutput *o)
 			&& !Labels) parent->Command(CMD_DELOBJ_CONT, this, o);
 		else if(bRedraw) parent->Command(CMD_REDRAW, NULL, o);
 		return bRedraw;
-	case CMD_HIDE_MARK:
-		if(!o || !tmp) return false;
-		if(bFound =(tmp == (void*)TheLine)) TheLine->DoMark(o, false);
-		else for(j = 5; j >= 0 && !bFound; j--){
-			if(obs[j]) for(i = 0; i < nPoints && !bFound; i++){
-				if(bFound = (tmp == (void*)obs[j][i])) obs[j][i]->DoMark(o, false);
-				else if(obs[j][i] && obs[j][i]->Id == GO_MLABEL &&
-					obs[j][i]->Command(cmd, tmp, o)) return true;
-				}
-			}
-		return bFound;
 	default:							//pass command to all objects
 		for(j = 0; j < 6; j++){
 			if(obs[j]) for(i = 0; i < nPoints; i++){
@@ -949,6 +950,44 @@ FreqDist::FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce):Plot(par,
 	Id = GO_FREQDIST;
 }
 
+FreqDist::FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses):Plot(par, d)
+{
+	int i, j;
+	int *cl_data;
+	Bar **bars;
+
+	FileIO(INIT_VARS);
+	ssRef = 0L;
+	plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
+	for(i = 0, dmin = HUGE_VAL, dmax = -HUGE_VAL; i < nvals; i++) {
+		if(vals[i] < dmin) dmin = vals[i];
+		if(vals[i] > dmax) dmax = vals[i];
+		}
+	start = dmin;		step = 1.00001*(dmax-dmin)/((double)nclasses);
+	if(!(cl_data = (int*)calloc(nclasses+1, sizeof(int)))) return;
+	for(i = 0; i < nvals; i++) {
+		j = (int)(floor((vals[i] - start)/step));
+		if(j >= 0 && j <= nclasses) cl_data[j]++;
+		}
+	if(cl_data[nclasses]) nclasses++;
+	if(bars = (Bar**)calloc(nclasses, sizeof(Bar*))) for(i = 0; i < nclasses; i++) {
+		if(bars[i] = new Bar(this, 0L, i*step+start, (double)cl_data[i], BAR_VERTB | BAR_RELWIDTH,
+			-1, -1, -1, -1, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
+		}
+	//create bar chart
+	if(bars && (plots[0] = new PlotScatt(this, data, nclasses, bars, 0L))){
+		plots[0]->Command(CMD_BAR_FILL, &BarFill, 0L);
+		plots[0]->SetColor(COL_BAR_LINE, BarLine.color);
+		plots[0]->SetSize(SIZE_BAR_LINE, BarLine.width);
+		}
+	if(plots[0]){
+		Bounds.Xmin = dmin;		Bounds.Xmax = dmax;
+		plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
+		}
+	free(cl_data);
+	Id = GO_FREQDIST;
+}
+
 FreqDist::FreqDist(int src):Plot(0L, 0L)
 {
 	FileIO(INIT_VARS);
@@ -1013,15 +1052,6 @@ FreqDist::Command(int cmd, void *tmpl, anyOutput *o)
 	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]) {
-				plots[i]->DoMark(o, false);
-				return true;
-				}
-			else if(plots[i]->Command(cmd, tmpl, o)) return true;
-			}
-		return false;
 	case CMD_DELOBJ:
 		if(plots && tmpl && parent) for(i = 0; i < nPlots; i++) if(plots[i]){
 			if(tmpl == (void*)plots[i]) {
@@ -1204,7 +1234,7 @@ FreqDist::ProcData(int sel)
 			}
 		free(s_data);		free(t_data);		free(f_data);
 		//create bar chart
-		if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars))){
+		if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars, 0L))){
 			plots[0]->Command(CMD_BAR_FILL, &BarFill, 0L);
 			plots[0]->SetColor(COL_BAR_LINE, BarLine.color);
 			plots[0]->SetSize(SIZE_BAR_LINE, BarLine.width);
@@ -1508,8 +1538,6 @@ 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_HIDE_MARK:
-		return false;
 	case CMD_SAVE_SYMBOLS:
 		return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
 	case CMD_UPDATE:
@@ -1890,28 +1918,6 @@ PolarPlot::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) 
 			((ObjTree*)tmpl)->Command(CMD_UPDATE, Plots[i], 0L);
 		return true;
-	case CMD_HIDE_MARK:
-		if(!tmpl || !o) return false;
-		//do all axes
-		if(Axes)for(i = nAxes-1; i>=0; i--) {
-			if(tmpl == (void*)Axes[i]){
-				Axes[i]->DoMark(CurrDisp, false);		return true;
-				}
-			else if(Axes[i]->Id == GO_AXIS) {
-				if(Axes[i]->Command(cmd, tmpl, o))		return true;
-				}
-			}
-		//do all plots
-		if(Plots)for(i = nPlots-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_MOUSE_EVENT:
 		if(hidden) return false;
 		if(o) switch(((MouseEvent*)tmpl)->Action) {
@@ -2152,6 +2158,9 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 		if(hidden) return false;
 		if(!CurrGO && ((MouseEvent*)tmpl)->Action == MOUSE_LBUP) return ForEach(cmd, tmpl, o);
 		return false;
+	case CMD_TEXTTHERE:
+		if(Labels) for(i = 0; i < nPoints; i++)	if(Labels[i] &&  Labels[i]->Command(cmd, tmpl, o))	return true;
+		return false;
 	case CMD_LEGEND:
 		if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
 		if(Symbols) {
@@ -2859,23 +2868,6 @@ StackBar::Command(int cmd, void *tmpl, anyOutput *o)
 			break;
 			}
 		break;
-	case CMD_HIDE_MARK:
-		if(!tmpl) return false;
-		if(Boxes && !CurrGO) for(i = 0; i < numPlots; i++)
-			if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o))return true;
-		if(xyPlots && !CurrGO) for(i = 0; i < numXY; i++)
-			if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o))return true;
-		if(Polygons && !CurrGO) for(i = 0; i < numPG; i++)
-			if(Polygons[i] && Polygons[i] == tmpl){
-				Polygons[i]->DoMark(o, false);
-				return true;
-				}
-		if(Lines && !CurrGO) for(i = 0; i < numPL; i++)
-			if(Lines[i] && Lines[i] == tmpl){
-				Lines[i]->DoMark(o, false);
-				return true;
-				}
-		break;
 	case CMD_OBJTREE:
 		if(!tmpl) return false;
 		if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) 
@@ -3480,23 +3472,6 @@ Scatt3D::Command(int cmd, void *tmpl, anyOutput *o)
 	MouseEvent *mev;
 
 	switch (cmd) {
-	case CMD_HIDE_MARK:
-		if(!o || !tmpl) return false;
-		if(rib && rib->Command(cmd, tmpl, o)) return true;
-		if(Line && (void*) Line == tmpl){
-			Line->DoMark(o, false);					return true;
-			}
-		if(Columns) for(i = 0; i < nColumns; i++) {
-			if(Columns[i] && (void*)Columns[i] == tmpl) {
-				Columns[i]->DoMark(o, false);		return true;
-				}
-			}
-		if(DropLines) for(i = 0; i < nDropLines; i++) {
-			if(DropLines[i] && (void*)DropLines[i] == tmpl) {
-				DropLines[i]->DoMark(o, false);		return true;
-				}
-			}
-		return false;
 	case CMD_MOUSE_EVENT:
 		if(hidden) return false;
 		mev = (MouseEvent *) tmpl;
@@ -4333,12 +4308,6 @@ Function::Command(int cmd, void *tmpl, anyOutput *o)
 		if(hidden) return false;
 		if(dl) return dl->Command(cmd, tmpl, o);
 		break;
-	case CMD_HIDE_MARK:
-		if(dl && tmpl == dl) {
-			dl->DoMark(o, false);
-			return true;
-			}
-		return false;
 	case CMD_SCALE:
 		Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;		Line.width *= ((scaleINFO*)tmpl)->sy.fy;
 		return true;
@@ -4402,7 +4371,9 @@ Function::Update(anyOutput *o, DWORD flags)
 	long ndata;
 
 	if(!parent || !cmdxy) return false;
+	LockData(false, false);
 	do_xyfunc(data, x1, x2, xstep, cmdxy, &xydata, &ndata, param);
+	LockData(false, false);
 	if(xydata && ndata >1) {
 		if(!dl) dl = new DataLine(this, data, xydata, ndata, name);
 		else dl->LineData(xydata, ndata);
@@ -4545,9 +4516,6 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *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;
 	case CMD_MOUSE_EVENT:
 		if(hidden) return false;
 		mev = (MouseEvent *) tmpl;
@@ -5009,29 +4977,6 @@ Plot3D::Command(int cmd, void *tmpl, anyOutput *o)
 		if(o) o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
 			Axes[1]->GetAxis(), Axes[2]->GetAxis());
 		return true;
-	case CMD_HIDE_MARK:
-		if(!tmpl) return false;
-		//do all axes
-		if(Axes)for(i = nAxes-1; i>=0; i--) if(Axes[i]){
-			if(tmpl == (void*)Axes[i]){
-				Axes[i]->DoMark(o, false);
-				return true;
-				}
-			else if(Axes[i]->Id == GO_AXIS) {
-				if(Axes[i]->Command(cmd, tmpl, o)) return true;
-				}
-			}
-		//do all plots
-		if(plots)for(i = nPlots-1; i>=0; i--) if(plots[i]){
-			if(tmpl == (void*)plots[i]){
-				plots[i]->DoMark(o, false);
-				return true;
-				}
-			else if(plots[i]->Id == GO_MLABEL || (plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH)) {
-				if(plots[i]->Command(cmd, tmpl, o)) return true;
-				}
-			}
-		return false;
 	case CMD_OBJTREE:
 		if(!tmpl || !plots) return false;
 		for(i = 0; i < nPlots; i++) if(plots[i]) {
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index 65c8e0e..4a6230d 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -42,85 +42,105 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Symbol properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *SymDlg_DlgTmpl = 
+	"1,+,,DEFAULT,PUSHBUTTON,-1,145,10,60,12\n"
+	".,.,,,PUSHBUTTON,2,145,25,60,12\n"
+	".,.,,,PUSHBUTTON,-2,145,40,60,12\n"
+	".,50,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	".,+,100,ISPARENT | CHECKED,SHEET,3,5,10,130,113\n"
+	".,.,200,TOUCHEXIT | ISPARENT,SHEET,4,5,10,130,113\n"
+	".,,300,ISPARENT,SHEET,5,5,10,130,113\n"
+	"50,,,TOUCHEXIT,SYMBUTT,0,155,75,40,40\n"
+	"100,+,,,RTEXT,6,5,25,45,8\n"
+	".,.,,TOUCHEXIT,INCDECVAL1,9,55,25,32,10\n"
+	".,.,,,LTEXT,-3,89,25,20,8\n"
+	".,.,,,RTEXT,10,5,37,45,8\n"
+	".,.,,TOUCHEXIT,INCDECVAL1,11,55,37,32,10\n"
+	".,.,,,LTEXT,-3,89,37,20,8\n"
+	".,.,,,RTEXT,12,5,49,45,8\n"
+	".,.,,TOUCHEXIT | OWNDIALOG, COLBUTT,13,55,49,25,10\n"
+	".,.,,,RTEXT,14,5,61,45,8\n"
+	".,401,,TOUCHEXIT | OWNDIALOG,COLBUTT,15,55,61,25,10\n"
+	"200,204,201,CHECKED | ISPARENT, GROUPBOX,16,12,28,50,39\n"
+	".,+,,TOUCHEXIT, RADIO1,17,15,33,45,8\n"
+	".,.,,TOUCHEXIT, RADIO1,18,15,43,45,8\n"
+	".,,,TOUCHEXIT, RADIO1,19,15,53,43,8\n"
+	".,250,205,CHECKED | ISPARENT, GROUPBOX,20,72,28,57,39\n"
+	"205,+,,TOUCHEXIT, CHECKBOX,21,75,33,25,8\n"
+	".,.,,TOUCHEXIT, CHECKBOX,22,75,43,25,8\n"
+	".,,,TOUCHEXIT, CHECKBOX,23,75,53,25,8\n"
+	"250,+,,TOUCHEXIT | CHECKED, RADIO1,24,10,75,45,8\n"
+	".,.,,,EDTEXT,25,60,75,68,10\n"
+	".,.,,TOUCHEXIT,RADIO1,26,10,92,60,8\n"
+	".,,,,EDTEXT,27,20,102,100,10\n"
+	"300,+,,,RTEXT,-12,5,30,45,8\n"
+	".,.,,,EDVAL1,7,55,30,45,10\n"
+	".,.,,,RTEXT,-13,5,50,45,8\n"
+	".,,,LASTOBJ,EDVAL1,8,55,50,45,10";
+
 bool
 Symbol::PropertyDlg()
 {
-	TabSHEET tab1 = {0, 45, 10, "Size & Color"};
-	TabSHEET tab2 = {110, 130, 10, "Edit"};
-	TabSHEET tab3 = {68, 110, 10, "Text Prop."};
-	TabSHEET tab4 = {45, 68, 10, "Text"};
+	TabSHEET tab1 = {0, 47, 10, "Size & Color"};
+	TabSHEET tab2 = {47, 70, 10, "Text"};
+	TabSHEET tab3 = {70, 92, 10, "Edit"};
 	Symbol *PrevSym = 0L;
 	char text1[40], text2[100];
-	int syms[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, SYM_TEXT};
-	DlgInfo SymDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to SYMBOL", 145, 10, 60, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 145, 25, 60, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 145, 40, 60, 12},
-		{4, 500, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 70},
-		{6, 7, 300, ISPARENT, SHEET, &tab2, 5, 10, 130, 70},
-		{7, 8, 200, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 130, 70},
-		{8, 401, 250, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 130, 70},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"size", 5, 25, 45, 8},
-		{101, 102, 0, TOUCHEXIT, INCDECVAL1, &size, 55, 25, 32, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 25, 20, 8},
-		{103, 104, 0, 0x0L, RTEXT, (void*)"line width", 5, 37, 45, 8},
-		{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, 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, 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},
-		{203, 0, 0, TOUCHEXIT, RADIO1, (void*)"Courier", 15, 55, 45, 8},
-		{204, 0, 205, CHECKED | ISPARENT, GROUPBOX, (void*)" style ", 72, 28, 57, 45},
-		{205, 206, 0, TOUCHEXIT, CHECKBOX, (void*)"bold", 75, 35, 25, 8},
-		{206, 207, 0, TOUCHEXIT, CHECKBOX, (void*)"italic", 75, 45, 25, 8},
-		{207, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"underlined", 75, 55, 25, 8},
-		{250, 251, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)"fixed text:", 10, 30, 45, 8},
-		{251, 252, 0, 0x0L, EDTEXT, text1, 60, 30, 45, 10},
-		{252, 253, 0, TOUCHEXIT, RADIO1, (void*)"from spreadsheet range:", 10, 45, 60, 8},
-		{253, 0, 0, 0x0L, EDTEXT, text2, 20, 55, 100, 10},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 5, 30, 45, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 55, 30, 45, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 5, 50, 45, 8},
-		{303, 0, 0, 0x0L, EDVAL1, &fPos.fy, 55, 50, 45, 10},
-		{401, 402, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[0], 15, 85, 10, 10},
-		{402, 403, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[1], 25, 85, 10, 10}, 
-		{403, 404, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[2], 35, 85, 10, 10}, 
-		{404, 405, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[3], 45, 85, 10, 10}, 
-		{405, 406, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[4], 55, 85, 10, 10}, 
-		{406, 407, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[5], 65, 85, 10, 10}, 
-		{407, 408, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[6], 75, 85, 10, 10}, 
-		{408, 409, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[7], 85, 85, 10, 10}, 
-		{409, 410, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[8], 95, 85, 10, 10}, 
-		{410, 411, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[9], 105, 85, 10, 10}, 
-		{411, 412, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[10], 115, 85, 10, 10}, 
-		{412, 413, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[11], 15, 95, 10, 10}, 
-		{413, 414, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[12], 25, 95, 10, 10}, 
-		{414, 415, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[13], 35, 95, 10, 10}, 
-		{415, 416, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[14], 45, 95, 10, 10}, 
-		{416, 0, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[15], 55, 95, 40, 10}, 
-		{500, 0, 0, LASTOBJ | TOUCHEXIT, SYMBUTT, (void*)&PrevSym, 155, 65, 40, 40}};
+	void *dyndata[] = {(void*)"Apply to Symbol", (void*)"Apply to PLOT", (void*)&tab1,
+		(void*)&tab2, (void*)&tab3, (void*)"size", (void*)&fPos.fx, (void*)&fPos.fy,
+		(void*)&size, (void*)"line width", (void*)&SymLine.width, (void*)"line color",
+		(void *)&SymLine.color, (void*)"fill color", (void *)&SymFill.color, (void*)" font ",
+		(void*)"Helvetica", (void*)"Times", (void*)"Courier", (void*)" style ", (void*)"bold",
+		(void*)"italic", (void*)"underlined", (void*)"fixed text:", (void*)text1,
+		(void*)"from spreadsheet range:", (void*)text2};
+	DlgInfo *SymDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpType, width, height;
+	int i, k, ix, iy, tmpType, res, width, height, n_syms;
 	DWORD tmpCol, undo_flags = 0L;
 	double tmpVal, o_size, n_size, o_lwidth, n_lwidth;
 	TextDEF textdef;
 	anyOutput *cdisp = Undo.cdisp;
 	lfPOINT o_pos, n_pos;
+	static const int syms[] = {SYM_CIRCLE, SYM_CIRCLEF, SYM_CIRCLEC, SYM_RECT, SYM_RECTF, SYM_RECTC, 
+		SYM_TRIAU, SYM_TRIAUF, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR, SYM_TRIAD, SYM_TRIADF, SYM_TRIADC,
+		SYM_TRIADL, SYM_TRIADR, SYM_DIAMOND, SYM_DIAMONDF, SYM_DIAMONDC, SYM_5GON, SYM_5GONF, SYM_5GONC,
+		SYM_4STAR, SYM_4STARF, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD,
+		SYM_3QUAD, SYM_PLUS, SYM_CROSS, SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT};
 
-	if(!parent) return false;
+	if(!(SymDlg = CompileDialog(SymDlg_DlgTmpl, dyndata)))return false;
 	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);
+	if(parent && 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);
+	if(parent && data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
 #endif
 	else rlp_strcpy(text2, 100, "(not available)");
+	n_syms = sizeof(syms)/sizeof(int);
+	for(k = 1; !(SymDlg[k-1].flags & LASTOBJ); k++);
+	if(!parent) n_syms--;
+	if(!(SymDlg = (DlgInfo *)realloc(SymDlg, (k+n_syms)*sizeof(DlgInfo)))) return false;
+	SymDlg[k-1].flags &= (~LASTOBJ);
+	for(i = 1, iy = 66; i <= n_syms; i++, ix += 10) {
+		if((i%11) == 1) {
+			iy += 10;		ix = 15;
+			}
+		SymDlg[k].id = 400 + i;					SymDlg[k].next = 400 + i + 1;
+		SymDlg[k].first = 0;					SymDlg[k].flags = TOUCHEXIT;
+		SymDlg[k].type = SYMRADIO;				SymDlg[k].ptype = (void*)&syms[i-1];
+		SymDlg[k].x = ix;						SymDlg[k].y = iy;
+		if(type == syms[i-1]) SymDlg[k].flags |= CHECKED;
+		SymDlg[k].w = SymDlg[k].h = 10;			k++;
+		}
+	SymDlg[k-1].flags |= LASTOBJ;				if(parent) SymDlg[k-1].w = 30;
+	if(parent) {
+		SymDlg[0].ptype = dyndata[0];
+		}
+	else {
+		SymDlg[5].flags |= HIDDEN;				SymDlg[6].flags |= HIDDEN;
+		SymDlg[1].flags |= HIDDEN;				SymDlg[2].y = 25;
+		SymDlg[0].w = SymDlg[2].w = 45;			SymDlg[7].x = 145;
+		}
 	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);
@@ -132,6 +152,7 @@ Symbol::PropertyDlg()
 		if(Command(CMD_GETTEXTDEF, &textdef, 0L))
 			PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
 		PrevSym->idx = idx;
+		SymDlg[7].ptype = (void*)&PrevSym;
 		}
 	if(PrevSym && (Dlg = new DlgRoot(SymDlg, data))) {
 		Dlg->TextFont(201, FONT_HELVETICA);
@@ -140,8 +161,6 @@ Symbol::PropertyDlg()
 		Dlg->TextStyle(205, TXS_BOLD);
 		Dlg->TextStyle(206, TXS_ITALIC);
 		Dlg->TextStyle(207, TXS_UNDERLINE);
-		if(type == SYM_TEXT) Dlg->SetCheck(416, 0L, true);
-		else Dlg->SetCheck(401+type, 0L, true);
 		switch(textdef.Font) {
 		case FONT_TIMES:	Dlg->SetCheck(202, 0L, true);	break;
 		case FONT_COURIER:	Dlg->SetCheck(203, 0L, true);	break;
@@ -152,13 +171,15 @@ Symbol::PropertyDlg()
 		if(textdef.Style & TXS_UNDERLINE) Dlg->SetCheck(207, 0L, true);
 		}
 	else return false;
-	if(parent->name) {
+	if(parent && 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;
+	else {
+		rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol properties");
+		}
+	if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, parent ? 430 : 400, 292, Dlg, 0x0L)))return false;
 	tmpCol = 0x00c0c0c0L;	o_size = size;	o_lwidth = SymLine.width;
 	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lwidth);
 	n_size = o_size;					n_lwidth = o_lwidth;
@@ -168,11 +189,10 @@ Symbol::PropertyDlg()
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
-		switch(res) {
-		case 2:
-		case 1:
+		switch(res){
+		case 1:		case 2:
 			Undo.SetDisp(cdisp);
-			if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
+			if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
 				Dlg->GetText(251, text1, 40);
 				if(PrevSym->Command(CMD_GETTEXT, (void *)text2, 0L) && strcmp(text1, text2)) {
 					PrevSym->Command(CMD_SETTEXT, (void *)text1, 0L);
@@ -180,18 +200,16 @@ Symbol::PropertyDlg()
 					res = -1;
 					}
 				}
-			else if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
+			else if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
 				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);
 			break;
-		case 7:											//the text sheets
-		case 8:
-			Dlg->SetCheck(416, 0L, true);
+		case 6:											//the text sheets
+			if(parent)Dlg->SetCheck(400+n_syms, 0L, true);
 			if(PrevSym->type != SYM_TEXT) {
-				PrevSym->type = SYM_TEXT;
-				Dlg->DoPlot(NULL);
+				PrevSym->type = SYM_TEXT;		Dlg->DoPlot(0L);
 				}
 			res = -1;
 			break;
@@ -206,26 +224,13 @@ Symbol::PropertyDlg()
 				if(Dlg->GetCheck(206)) textdef.Style |= TXS_ITALIC;
 				if(Dlg->GetCheck(207)) textdef.Style |= TXS_UNDERLINE;
 				PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
-				Dlg->DoPlot(NULL);
+				Dlg->DoPlot(0L);
 				}
 			res = -1;
 			break;
-		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,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;
-			break;
-		case 401:	case 402:	case 403:	case 404:	//symbol selection
-		case 405:	case 406:	case 407:	case 408:
-		case 409:	case 410:	case 411:	case 412:
-		case 413:	case 414:	case 415:
-			tmpType = res - 401;
-		case 416:										//text symbol
-			if(res == 416) tmpType = SYM_TEXT;
+		default:										//symbol selection ?
+			if(res > 400 && res <= (400+n_syms)) tmpType = syms[res-401];
+			else break;
 			PrevSym->type = tmpType;
 		case 107:										//line color button
 			if(res == 107 && Dlg->GetColor(107, &tmpCol))
@@ -235,7 +240,7 @@ Symbol::PropertyDlg()
 				PrevSym->SetColor(COL_SYM_FILL, tmpCol);
 		case 101:										//symbol size changed
 		case 104:										//line width changed
-		case 500:										//preview button
+		case 50:										//preview button
 			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) {
@@ -243,6 +248,15 @@ Symbol::PropertyDlg()
 				else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2,100))	
 					PrevSym->Command(CMD_RANGETEXT, text2, 0L);
 				}
+			Dlg->DoPlot(0L);
+			res = -1;
+			break;
+		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,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;
 			break;
@@ -270,6 +284,7 @@ Symbol::PropertyDlg()
 		break;
 	case 2:								//accept values for all symbols of plot
 		parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+		undo_flags |= UNDO_CONTINUE;
 		parent->SetSize(SIZE_SYMBOL, n_size);
 		parent->SetSize(SIZE_SYM_LINE, n_lwidth);
 		if(Dlg->GetColor(107, &tmpCol))	parent->SetColor(COL_SYM_LINE, tmpCol);
@@ -285,10 +300,8 @@ Symbol::PropertyDlg()
 			}
 		break;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
-	delete PrevSym;
-	return true;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(SymDlg);
+	delete PrevSym;			return undo_flags != 0;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -431,45 +444,45 @@ Bubble::PropertyDlg()
 		bRet = true;
 		break;
 		}
-	CloseDlgWnd(hDlg);		delete Dlg;		return bRet;		free(BubDlg);
+	CloseDlgWnd(hDlg);		delete Dlg;			free(BubDlg);		return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // 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"
+	"1,+,,DEFAULT,PUSHBUTTON,1,130,10,55,12\n"
+	".,.,,,PUSHBUTTON,2,130,25,55,12\n"
+	".,.,,,PUSHBUTTON,-2,130,40,55,12\n"
+	".,,5,CHECKED | ISPARENT,GROUP,0,138,40,55,12\n"
+	"5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,120\n"
+	".,.,200,ISPARENT,SHEET,4,5,10,120,120\n"
+	".,,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";
+	"109,+,,,LTEXT,7,10,80,45,8\n"
+	".,.,,,RADIO1,8,20,92,25,8\n"
+	".,.,,,EDTEXT,9,60,92,25,10\n"
+	".,.,,,LTEXT,-3,87,92,20,8\n"
+	".,.,,,RADIO1,10,20,104,25,8\n"
+	".,.,,,EDTEXT,11,60,104,25,10\n"
+	".,,,,LTEXT,-10,87,104,10,8\n"
+	"200,+,,TOUCHEXIT,RADIO2,12,20,30,45,8\n"
+	".,205,202,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	".,+,,TOUCHEXIT,RADIO1,13,30,40,35,8\n"
+	".,.,,TOUCHEXIT,RADIO1,14,30,48,35,8\n"
+	".,,,TOUCHEXIT,RADIO1,15,30,56,35,8\n"
+	"205,+,,,EDVAL1,16,65,56,35,10\n"
+	".,.,,TOUCHEXIT,RADIO2,17,20,70,45,8\n"
+	".,211,208,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"208,+,,TOUCHEXIT,RADIO1,18,30,80,35,8\n"
+	".,.,,TOUCHEXIT,RADIO1,19,30,88,35,8\n"
+	".,,,TOUCHEXIT,RADIO1,20,30,96,35,8\n"
+	"211,+,,,EDVAL1,21,65,96,35,10\n"
+	".,,,,CHECKBOX,22,20,113,50,8\n"
+	"300,+,,,RTEXT,-12,10,50,45,8\n"
+	".,.,,,EDVAL1,23,60,50,40,10\n"
+	".,.,,,RTEXT,-13,10,75,45,8\n"
+	".,,,LASTOBJ,EDVAL1,24,60,75,40,10";
 bool
 Bar::PropertyDlg()
 {
@@ -801,7 +814,7 @@ RegLine::PropertyDlg()
 	TabSHEET tab1 = {0, 30, 10, "Line"};
 	TabSHEET tab2 = {30, 60, 10, "Model"};
 	TabSHEET tab3 = {60, 95, 10, "Clipping"};
-	char text1[40], text2[40], text3[40], text4[40], text5[40];
+	char text1[60], text2[60], text3[60], text4[60], text5[60];
 	DlgInfo LineDlg[] = {
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 45, 12},
 		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 45, 12},
@@ -863,11 +876,11 @@ RegLine::PropertyDlg()
 	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);
+	sprintf_s(text1, 60, "%s = %.3lf + %.3lf * %s   (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
+	sprintf_s(text2, 60, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
+	sprintf_s(text3, 60, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
+	sprintf_s(text4, 60, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
+	sprintf_s(text5, 60, "%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);
@@ -973,30 +986,39 @@ RegLine::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // SDellipse properties
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* SdEllipseDlg_Tmpl = 
+	"1,+,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,150,25,45,12\n"
+	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,139,140\n"
+	".,,200,ISPARENT,SHEET,2,5,10,139,140\n"
+	"100,,,NOSELECT,ODBUTTON,3,10,48,130,100\n"
+	"200,+,,,CHECKBOX,4,20,26,80,9\n"
+	".,.,250,CHECKED, GROUPBOX,5,10,45,129,100\n"
+	"250,+,,,LTEXT,6,25,82,60,8\n"
+	".,.,,,RTEXT,7,20,92,60,8\n"
+	".,.,,,LTEXT,0,82,92,30,8\n"
+	".,.,,,RTEXT,8,20,100,60,8\n"
+	".,.,,,LTEXT,0,82,100,30,8\n"
+	".,.,,,LTEXT,9,25,112,60,8\n"
+	".,.,,,RTEXT,10,20,122,60,8\n"
+	".,.,,,LTEXT,0,82,122,30,8\n"
+	".,.,,,RTEXT,11,20,130,60,8\n"
+	".,.,,,LTEXT,0,82,130,30,8\n"
+	".,.,,,LTEXT,12,25,52,30,8\n"
+	".,.,,,RADIO1,13,50,52,30,8\n"
+	".,.,,,RADIO1,14,50,61,30,8\n"
+	".,,,LASTOBJ,RADIO1,15,50,70,30,8";
 bool
 SDellipse::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 40, 10, "Line"};
 	TabSHEET tab2 = {40, 80, 10, "Details"};
-	DlgInfo ellDlg[] = {
-		{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, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
-		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
-		{200, 201, 0, 0x0L, CHECKBOX, (void*)" show regression line", 20, 30, 80, 9},
-		{201, 0, 250, CHECKED, GROUPBOX, (void*)"  ellipse  ", 10, 55, 129, 70},
-		{250, 251, 0, 0x0L, LTEXT, (void*)"center (means of data)", 25, 60, 60, 8},
-		{251, 252, 0, 0x0L, RTEXT, (void*)"x =", 20, 70, 60, 8},
-		{252, 253, 0, 0x0L, LTEXT, 0L, 82, 70, 30, 8},
-		{253, 254, 0, 0x0L, RTEXT, (void*)"y =", 20, 78, 60, 8},
-		{254, 255, 0, 0x0L, LTEXT, 0L, 82, 78, 30, 8},
-		{255, 256, 0, 0x0L, LTEXT, (void*)"standard deviation (SD)", 25, 90, 60, 8},
-		{256, 257, 0, 0x0L, RTEXT, (void*)"major axis =", 20, 100, 60, 8},
-		{257, 258, 0, 0x0L, LTEXT, 0L, 82, 100, 30, 8},
-		{258, 259, 0, 0x0L, RTEXT, (void*)"minor axis =", 20, 108, 60, 8},
-		{259, 0, 0, LASTOBJ, LTEXT, 0L, 82, 108, 30, 8}};
+	void *dyndata[] = {(void*)&tab1, (void*) &tab2, (void*)OD_linedef, (void*)" show regression line",
+		(void*)"  ellipse  ", (void*)"center (means of data)", (void*)"x =", (void*)"y =",
+		(void*)"standard deviation (S.D.)", (void*)"major axis", (void*)"minor axis", (void*)"size:",
+		(void*)" 1 x S.D.", (void*)" 2 x S.D.", (void*)" 3 x S.D."};
+	DlgInfo *ellDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int cb, res, tmpType;
@@ -1006,6 +1028,7 @@ SDellipse::PropertyDlg()
 	anyOutput *cdisp = Undo.cdisp;
 
 	if(!parent) return false;
+	if(!(ellDlg = CompileDialog(SdEllipseDlg_Tmpl, dyndata))) return false;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
 	if(!(Dlg = new DlgRoot(ellDlg, data))) return false;
 	if(!(type & 0x10000)) Dlg->SetCheck(200, 0L, true);
@@ -1014,13 +1037,18 @@ SDellipse::PropertyDlg()
 	rlp_strcpy(TmpTxt, 4, "+/-");
 	WriteNatFloatToBuff(TmpTxt+3, sd1);		Dlg->SetText(259, TmpTxt);
 	WriteNatFloatToBuff(TmpTxt+3, sd2);		Dlg->SetText(257, TmpTxt);
+	switch(type & 0x60000) {
+		case 0x20000:	Dlg->SetCheck(262, 0L, true);	break;
+		case 0x40000:	Dlg->SetCheck(263, 0L, true);	break;
+		default:		Dlg->SetCheck(261, 0L, true);	break;
+		}
 	tmpType = type;
 	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);
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 340, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -1034,10 +1062,13 @@ SDellipse::PropertyDlg()
 			}
 		if(Dlg->GetCheck(200)) tmpType &= ~0x10000;
 		else tmpType |= 0x10000;
+		tmpType &= ~0x60000;
+		if(Dlg->GetCheck(262)) tmpType |= 0x20000;
+		else if(Dlg->GetCheck(263)) tmpType |= 0x40000;
 		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
 		if(undo_flags & UNDO_CONTINUE) bRet = true;
 		}
-	CloseDlgWnd(hDlg);		delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(ellDlg);
 	return bRet;
 }
 
@@ -2297,10 +2328,11 @@ Label::PropertyDlg()
 		{107, 108, 0, 0x0L, RTEXT, (void*)"rotation", 30, 57, 45, 8},
 		{108, 109, 0, 0x0L, EDVAL1, &TextDef.RotBL, 80, 57, 25, 10},
 		{109, 150, 0, 0x0L, LTEXT, (void *)"deg.", 107, 57, 20, 8},
-		{150, 105, 151, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+		{150, 154, 151, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
 		{151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 30, 69, 45, 8},
 		{152, 153, 0, 0x0L, INCDECVAL1, &lspc, 80, 69, 33, 10},
 		{153, 0, 0, 0x0L, LTEXT, (void *)"%", 115, 69, 20, 8},
+		{154, 105, 0, 0x0L, CHECKBOX, (void*) " moveable", 80, 83, 60, 9},
 		{200, 244, 221, CHECKED | ISPARENT, GROUPBOX, (void*)" font ", 17, 28, 60, 50},
 		{221, 222, 0, TOUCHEXIT, RADIO1, (void*)"Helvetica", 20, 35, 45, 8},
 		{222, 223, 0, TOUCHEXIT, RADIO1, (void*)"Times", 20, 45, 45, 8},
@@ -2356,6 +2388,9 @@ Label::PropertyDlg()
 		Dlg->TextStyle(205, TXS_BOLD);			Dlg->TextStyle(206, TXS_ITALIC);
 		Dlg->TextStyle(207, TXS_UNDERLINE);		Dlg->TextStyle(207, TXS_SUPER);
 		Dlg->TextStyle(207, TXS_SUB);
+		if(moveable){
+			Dlg->SetCheck(154, 0L, true);
+			}
 		switch(TextDef.Font) {
 		case FONT_TIMES:	Dlg->SetCheck(222, 0L, true);	break;
 		case FONT_COURIER:	Dlg->SetCheck(223, 0L, true);	break;
@@ -2504,6 +2539,11 @@ Label::PropertyDlg()
 			o_dist.fy != n_dist.fy)){
 			pa->Command(CMD_SAVE_TICKS, 0L, 0L);			undo_flags |= UNDO_CONTINUE;
 			}
+		i = Dlg->GetCheck(154) ? 1 : 0;
+		if(i != moveable) {
+			Undo.ValInt(parent, &moveable, undo_flags);
+			moveable = i;									undo_flags |= UNDO_CONTINUE;
+			}
 		TmpTxt[0] = 0;		Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
 		if(res == 1) undo_flags = CheckNewString(&TextDef.text, TextDef.text, TmpTxt, this, undo_flags);
 		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
@@ -2552,6 +2592,9 @@ Label::PropertyDlg()
 	return RetVal;
 }
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Text frame properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool
 TextFrame::PropertyDlg()
 {
@@ -3201,10 +3244,11 @@ PlotScatt::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	int c, i, j, k, l, i1, j1, k1, l1, m, n, o, p, ic;
-	int ErrType = 0, res, BarType;
+	int ErrType = 0, res, BarType, nVals, nTxt, nTime;
 	double x, y, e;
 	lfPOINT fp1, fp2;
-	bool bRet = false, bLayout = false, bContinue = false;
+	bool bRet = false, bLayout = false, bContinue = false, bValid;
+	anyResult xRes, yRes;
 	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;
@@ -3317,6 +3361,15 @@ PlotScatt::PropertyDlg()
 		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;
 		data_desc = rY->RangeDesc(data, 1);
+		//analyse data types
+		if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+			}
+		if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+			}
 		//Create graphic objects
 		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
 		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
@@ -3346,7 +3399,35 @@ PlotScatt::PropertyDlg()
 		if(Dlg->GetCheck(250) && nPoints >1) TheLine = new DataLine(this, data, xRange, yRange); 
 		else if(Dlg->GetCheck(251) && nPoints >2) TheLine = new DataPolygon(this, data, xRange, yRange); 
 		do {
-			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+			bValid = false;
+			if(data->GetResult(&xRes, j, i, false) && data->GetResult(&yRes, l, k, false)) {
+				bValid = true;
+				if(x_tv) {
+					if(xRes.type == ET_TEXT) x = x_tv->GetValue(xRes.text);
+					else bValid = false;
+					}
+				else if(x_dtype == ET_DATETIME) {
+					if(xRes.type == ET_DATE || xRes.type == ET_TIME  || xRes.type == ET_DATETIME) x = xRes.value;
+					else bValid = false;
+					}
+				else {
+					if(xRes.type == ET_VALUE) x = xRes.value;
+					else bValid = false;
+					}
+				if(y_tv) {
+					if(yRes.type == ET_TEXT) y = y_tv->GetValue(yRes.text);
+					else bValid = false;
+					}
+				else if(y_dtype == ET_DATETIME) {
+					if(yRes.type == ET_DATE || yRes.type == ET_TIME  || yRes.type == ET_DATETIME) y = yRes.value;
+					else bValid = false;
+					}
+				else {
+					if(yRes.type == ET_VALUE) y = yRes.value;
+					else bValid = false;
+					}
+				}
+			if(bValid){
 				if(Symbols && (Symbols[ic] = new Symbol(this, data, x, y, DefSym, i, j, k, l))){
 					Symbols[ic]->idx = c;
 					}
@@ -3689,35 +3770,41 @@ FreqDist::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Regression properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* RegDlg_Tmpl = 
+	"1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
+	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,130,85\n"
+	".,10,200,ISPARENT,SHEET,2,5,10,130,85\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,+,,,LTEXT,3,10,22,60,8\n"
+	".,.,,,RANGEINPUT,-16,20,32,100,10\n"
+	".,.,,,LTEXT,4,10,45,60,8\n"
+	".,.,,,RANGEINPUT,-17,20,55,100,10\n"
+	".,.,,CHECKED,CHECKBOX,5,10,70,100,8\n"
+	".,,,,CHECKBOX,6,10,80,100,8\n" 
+	"200,210,201,CHECKED | ISPARENT, GROUPBOX,7,10,30,58,56\n"
+	"201,+,,CHECKED, RADIO1,8,20,40,30,8\n"
+	".,.,,,RADIO1,9,20,50,30,8\n"
+	".,.,,,RADIO1,10,20,60,30,8\n"
+	".,,,,RADIO1,11,20,70,30,8\n"
+	"210,,211,CHECKED | ISPARENT,GROUPBOX,12,72,30,58,56\n"
+	".,+,,CHECKED,RADIO1,13,82,40,30,8\n"
+	".,.,,,RADIO1,14,82,50,30,8\n"
+	".,.,,,RADIO1,15,82,60,30,8\n"
+	".,,,LASTOBJ,RADIO1,16,82,70,30,8";
+
 bool
 Regression::PropertyDlg()
 {
-	TabSHEET tab1 = {0, 40, 10, "Data"};
-	TabSHEET tab2 = {40, 90, 10, "Transform"};
-	char text1[100], text2[100];
-	DlgInfo RegDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 85},
-		{5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 130, 85},
-		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 20, 60, 8},
-		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 30, 100, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 45, 60, 8},
-		{103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 55, 100, 10},
-		{104, 105, 0, CHECKED, CHECKBOX, (void*)" include symbols in plot", 10, 70, 100, 8},
-		{105, 0, 0, 0x0L, CHECKBOX, (void*) " draw SD ellipse", 10, 80, 100, 8}, 
-		{200, 210, 201, CHECKED | ISPARENT, GROUPBOX, (void*)"  x-values  ", 10, 30, 58, 50},
-		{201, 202, 0, CHECKED, RADIO1, (void*)"x = x", 20, 40, 30, 8},
-		{202, 203, 0, 0x0L, RADIO1, (void*)"x = log(x)", 20, 48, 30, 8},
-		{203, 204, 0, 0x0L, RADIO1, (void*)"x = 1/x", 20, 56, 30, 8},
-		{204, 0, 0, 0x0L, RADIO1, (void*)"x = sqrt(x)", 20, 64, 30, 8},
-		{210, 0, 211, CHECKED | ISPARENT, GROUPBOX, (void*)"  y-values  ", 72, 30, 58, 50},
-		{211, 212, 0, CHECKED, RADIO1, (void*)"y = y", 82, 40, 30, 8},
-		{212, 213, 0, 0x0L, RADIO1, (void*)"y = log(y)", 82, 48, 30, 8},
-		{213, 214, 0, 0x0L, RADIO1, (void*)"y = 1/y", 82, 56, 30, 8},
-		{214, 0, 0, LASTOBJ, RADIO1, (void*)"y = sqrt(y)", 82, 64, 30, 8}};
+	TabSHEET tab1 = {0, 28, 10, "Data"};
+	TabSHEET tab2 = {28, 70, 10, "Transform"};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"range for X Data",
+		(void*)"range for Y Data", (void*)" include symbols in plot", (void*) " draw SD ellipse",
+		(void*)"  x-values  ", (void*)"x = x", (void*)"x = log(x)", (void*)"x = 1/x",
+		(void*)"x = sqrt(x)", (void*)"  y-values  ", (void*)"y = y", (void*)"y = log(y)",
+		(void*)"y = 1/y",(void*)"y = sqrt(y)"};
+	DlgInfo *RegDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int c, i, j, k, l, ic, res, n;
@@ -3727,10 +3814,11 @@ Regression::PropertyDlg()
 	lfPOINT *values = 0L;
 
 	if(!parent || !data) return false;
+	if(!(RegDlg = CompileDialog(RegDlg_Tmpl, dyndata))) return false;
 	rX = rY = 0L;
-	UseRangeMark(data, 1, text1, text2);
+	UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200);
 	if(!(Dlg = new DlgRoot(RegDlg, data)))return false;
-	hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 225, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 230, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -3817,7 +3905,7 @@ Regression::PropertyDlg()
 			c++;
 			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
 		if(ic) {
-			if(Dlg->GetCheck(105) && (sde = new SDellipse(this, data, values, ic, type | 0x2))&&
+			if(Dlg->GetCheck(105) && (sde = new SDellipse(this, data, values, ic, type | 0x20002))&&
 				(bRet= sde->Command(CMD_INIT, 0L, 0L)))sde->Command(CMD_BOUNDS, &Bounds, 0L);
 			else if((rLine = new RegLine(this, data, values, ic, type)) && 
 				(bRet= rLine->PropertyDlg()))rLine->Command(CMD_BOUNDS, &Bounds, 0L);
@@ -3826,7 +3914,7 @@ Regression::PropertyDlg()
 	CloseDlgWnd(hDlg);
 	delete Dlg;
 	if(rX) delete rX;	if(rY) delete rY;
-	if(values) free(values);
+	free(RegDlg);		if(values) free(values);
 	return bRet;
 }
 
@@ -4892,79 +4980,120 @@ StackBar::PropertyDlg()
 // create grouped bars chart
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char *GBDlg_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,90\n"
-	"5,6,200,ISPARENT,SHEET,2,5,10,120,90\n"
-	"6,10,300,ISPARENT,SHEET,3,5,10,120,90\n"
+	"1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
+	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,+,99,ISPARENT | CHECKED | TOUCHEXIT,SHEET,1,5,10,128,100\n"
+	".,.,200,ISPARENT,SHEET,2,5,10,128,100\n"
+	".,.,300,ISPARENT,SHEET,3,5,10,128,100\n"
+	".,10,250,ISPARENT | TOUCHEXIT,SHEET,16,5,10,128,100\n"
 	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
-	"100,101,,,LTEXT,4,10,25,60,8\n"
-	"101,150,,,LTEXT,5,10,33,60,8\n"
-	"150,,153,ISPARENT | CHECKED,GROUPBOX,6,10,50,110,45\n"
-	"153,154,,,LTEXT,0,15,55,60,8\n"
-	"154,155,,,RANGEINPUT,-1,15,65,100,10\n"
-	"155,156,,,PUSHBUTTON,-8,85,77,30,12\n"
-	"156,,,,PUSHBUTTON,-9,50,77,35,12\n"
-	"200,201,,,RTEXT,7,10,35,38,8\n"
-	"201,202,,,EDVAL1,8,58,35,35,10\n"
-	"202,203,,,RTEXT,9,10,50,38,8\n"
-	"203,204,,,EDVAL1,10,58,50,35,10\n"
-	"204,205,,,RTEXT,11,10,65,38,8\n"
-	"205,206,,,EDVAL1,12,58,65,35,10\n"
-	"206,207,,,LTEXT,-10,95,65,8,8\n"
-	"207,208,,,RTEXT,13,10,80,38,8\n"
-	"208,209,,,EDVAL1,14,58,80,35,10\n"
-	"209,,,,LTEXT,-10,95,80,8,8\n"
-	"300,,,LASTOBJ | NOSELECT,ODBUTTON,15,20,30,90,60";
+	"99,100,110,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"100,,160,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"101,+,,,LTEXT,0,25,39,60,8\n"
+	".,.,,,RANGEINPUT,-15,25,49,100,10\n"
+	".,.,,,LTEXT,0,25,61,60,8\n"
+	".,.,,,RANGEINPUT,-16,25,71,100,10\n"
+	".,.,,,PUSHBUTTON,-8,95,87,30,12\n"
+	".,,,,PUSHBUTTON,-9,60,87,35,12\n"
+	"110,+,,,LTEXT,4,10,25,60,8\n"
+	".,150,,,LTEXT,5,10,33,60,8\n"
+	"150,,153,ISPARENT | CHECKED,GROUPBOX,6,10,50,118,55\n"
+	"160,101,,ISPARENT | CHECKED,GROUPBOX,19,10,30,118,75\n"
+	"153,+,,,LTEXT,0,15,60,60,8\n"
+	".,.,,,RANGEINPUT,-1,15,70,108,10\n"
+	".,.,,,PUSHBUTTON,-8,93,87,30,12\n"
+	".,,,,PUSHBUTTON,-9,58,87,35,12\n"
+	"200,+,,,RTEXT,7,10,35,38,8\n"
+	".,.,,,EDVAL1,8,58,35,35,10\n"
+	".,.,,,RTEXT,9,10,50,38,8\n"
+	".,.,,,EDVAL1,10,58,50,35,10\n"
+	".,.,,,RTEXT,11,10,65,38,8\n"
+	".,.,,,EDVAL1,12,58,65,35,10\n"
+	".,.,,,LTEXT,-10,95,65,8,8\n"
+	".,.,,,RTEXT,13,10,80,38,8\n"
+	".,.,,,EDVAL1,14,58,80,35,10\n"
+	".,,,,LTEXT,-10,95,80,8,8\n"
+	"250,+,TOUCHEXIT,CHECKED,RADIO1,17,20,35,70,8\n"
+	".,.,,TOUCHEXIT,RADIO1,18,20,50,70,8\n"
+	".,,,,RANGEINPUT,0,15,65,108,10\n"
+	"300,,,LASTOBJ | NOSELECT,ODBUTTON,15,24,30,90,60";
 
 bool
 GroupBars::PropertyDlg()
 {
-	TabSHEET tab1 = {0, 25, 10, "Data"};
-	TabSHEET tab2 = {25, 55, 10, "Details"};
-	TabSHEET tab3 = {55, 90, 10, "Scheme"};
+	TabSHEET tab1 = {0, 27, 10, "Data"};
+	TabSHEET tab2 = {27, 59, 10, "Details"};
+	TabSHEET tab3 = {59, 96, 10, "Scheme"};
+	TabSHEET tab4 = {96, 128, 10, "Labels"};
 	double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"Get values from spreadsheet:",
 		(void*)"All ranges should have equal size!", (void*)" ranges for y values ", (void*)"start value",
 		(void*)&start, (void*)"group step", (void*)&step, (void*)"bar width", (void*)&bw,
-		(void*)"group gap", (void*)&gg, (void*)(OD_scheme)};
+		(void*)"group gap", (void*)&gg, (void*)(OD_scheme), (void*)&tab4, (void*)" no group labels",
+		(void*)"from spreadsheet range:", (void*)" ranges for y- and error- data "};
 	DlgInfo *GBDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
-	bool bRet = false, updateYR = true, bContinue = false;
-	char **rd = 0L, *desc;
+	bool bRet = false, updateYR = true, bContinue = false, bError;
+	char **rd=0L, **rdx=0L, **rdy=0L, *desc;
 	Bar **bars = 0L;
-	AccRange *rY = 0L;
-	int i, j, ic, res, ix, iy, ny, sc = 0, currYR = 0, maxYR = 0;
-	double x, y, xinc;
-
+	ErrorBar **errs = 0L;
+	AccRange *rX = 0L, *rY = 0L;
+	anyResult ares;
+	int i, j, ic, res, ix, iy, ex, ey, ny, s1, s2, sc = 0, currYR = 0, maxYR = 0;
+	double x, y, xinc, e, ebw;
+	
 	if(!parent || !data) return false;
 	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(!(GBDlg = CompileDialog(GBDlg_Tmpl, dyndata)))return false;
-	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+	if(mode == 0 && TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
 		for(i=0, j= 0; i <= 1000; i +=100) 
 			if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
 			maxYR = j-1;
 		}
+	else if(mode == 1 && TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*))) 
+		&& (rdy = (char**)calloc(12, sizeof(char*)))) {
+		for(i=j=0; i <= 1000; i +=200) if(TmpTxt[i]) {
+			rdx[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt)+1, 0);	
+			rdy[j] = (char*)memdup(TmpTxt+i+100, (int)strlen(TmpTxt+i+100)+1, 0);		maxYR = j++;
+			}
+		}
 	Id = GO_STACKBAR;
-	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+	if(mode == 0 && !rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+	if(mode == 1 && !rdx && !rdy && !(rdx = (char**)calloc(1, sizeof(char*))) 
+		&& !(rdy = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(GBDlg, data)))return false;
+	if(mode == 1) {
+		Dlg->ShowItem(99, false);		Dlg->ShowItem(100, true);
+		}
+	else {
+		Dlg->ShowItem(99, true);		Dlg->ShowItem(100, false);
+		}
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	else Dlg->SetText(154, "");
-	hDlg = CreateDlgWnd("Grouped bar chart", 50, 50, 370, 240, Dlg, 0x0L);
+	hDlg = CreateDlgWnd(mode == 0 ? (char*)"Grouped Bar Chart" : (char*)"Grouped Bar Chart with Error Bars", 50, 50, 390, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
-			if(currYR >0) Dlg->ShowItem(156, true);
-			else Dlg->ShowItem(156, false);
+			if(currYR >0) {
+				Dlg->ShowItem(156, true);		Dlg->ShowItem(106, true);
+				}
+			else {
+				Dlg->ShowItem(156, false);		Dlg->ShowItem(106, false);		
+				}
 #ifdef USE_WIN_SECURE
 			sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
+			sprintf_s(TmpTxt+100, 20, "errors # %d/%d", currYR+1, maxYR+1);
 #else
 			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+			sprintf(TmpTxt+100,"errors # %d/%d", currYR+1, maxYR+1);
 #endif
 			//SetText will also cause a redraw of the whole dialog
-			Dlg->SetText(153, TmpTxt);
+			if(mode == 0) 	Dlg->SetText(153, TmpTxt);
+			else {
+				Dlg->SetText(101, TmpTxt);		Dlg->SetText(103, TmpTxt+100);
+				}
 			updateYR = false;
 			}
 		LoopDlgWnd();
@@ -4976,17 +5105,117 @@ GroupBars::PropertyDlg()
 		case -1:
 			bContinue = false;
 			break;
+		case 250:		case 251:
+		case 7:
+			Dlg->Activate(252, true);
+			res = -1;			break;
+		case 4:
+			Dlg->Activate(mode ? 102:154, true);
+			res = -1;			break;
 		case 1:		
 			Dlg->GetValue(201, &start);			Dlg->GetValue(203, &step);
 			Dlg->GetValue(205, &bw);			Dlg->GetValue(208, &gg);
+			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+				&rY, &bContinue, &ny, &maxYR, &updateYR);
+			if(!mode) break;
+		case 105:										//next button
+			bError=false;	s1 = s2 = 0;
+			if(Dlg->GetText(102, TmpTxt, 100)) {
+				if(rX = new AccRange(TmpTxt)) {
+					s1 = rX->CountItems();
+					if(s1 < 2) {
+						ErrorBox("y-range not valid");
+						bContinue=bError=true;
+						Dlg->Activate(102, true);
+						}
+					delete rX;
+					}
+				else bError = true;
+				}
+			else bError = true;
+			if(Dlg->GetText(104, TmpTxt+100, 100) && !bError) {
+				if(rY = new AccRange(TmpTxt+100)) {
+					s2 = rY->CountItems();
+					if(s2 < 2) {
+						ErrorBox("error-range not valid");
+						bContinue=bError=true;
+						Dlg->Activate(104, true);
+						}
+					delete rY;
+					}
+				else bError = true;
+				}
+			else {
+				Dlg->Activate(104, true);
+				bError = true;
+				}
+			if(!s1 || !s2) bError = true;
+			rX = rY = 0L;
+			if(!bError && s1!=s2) {
+				ErrorBox("Y-range and error-range are\ndifferent in size");
+				bContinue=bError=true;
+				}
+			if(!bError) {
+				if((currYR+1) > maxYR) {
+					rdx = (char**)realloc(rdx, sizeof(char*)*(currYR+2));
+					rdy = (char**)realloc(rdy, sizeof(char*)*(currYR+2));
+					rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
+					maxYR = currYR+1;
+					}
+				if(rdx[currYR]) free(rdx[currYR]);		//store x-range
+				rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+				if(rdy[currYR]) free(rdy[currYR]);		//store y range
+				rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
+				updateYR = true;						currYR++;
+				Dlg->SetText(102, rdx[currYR]);			Dlg->SetText(104, rdy[currYR]);
+				Dlg->Activate(102, true);				
+				if(res != 1) res = -1;
+				}
+			else if(res != 1){
+				bContinue = true;
+				res = -1;
+				}
+			break;
+		case 106:										//prev button
+			if(Dlg->GetText(102, TmpTxt, 100) && Dlg->GetText(104, TmpTxt+100, 100)){
+				if(rdx[currYR]) free(rdx[currYR]);		if(rdy[currYR]) free(rdy[currYR]);
+				rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+				rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
+				}
+			else if(currYR == maxYR) maxYR--;
+			currYR--;	
+			Dlg->SetText(102, rdx[currYR]);
+			Dlg->SetText(104, rdy[currYR]);				Dlg->Activate(102, true);
+			updateYR = true;
+			res = -1;
+			break;
 		case 155:		case 156:
 			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
 				&rY, &bContinue, &ny, &maxYR, &updateYR);
 			break;
 			}
 		} while(res < 0);
-	if(res == 1 && rd && rd[0] && rd[0][0]){	//accept settings and create plots
-		if(rd[maxYR]) maxYR++;
+	if(res == 1 && ((rd && rd[0] && rd[0][0])||(rdx && rdy && rdx[0] && rdy[0] && rdx[0][0] && rdy[0][0]))){
+		//accept settings and create plots
+		if((mode == 0 && rd[maxYR]) || (mode == 1 && rdx[maxYR])) maxYR++;
+		ebw = defs.GetSize(SIZE_ERRBAR)*9.0/((double)(s1*maxYR));
+		if(Dlg->GetCheck(251) && Dlg->GetText(252, TmpTxt, 100) && (rX = new AccRange(TmpTxt))
+			&& rX->GetFirst(&ix, &iy)){
+			x_tv = new TextValue();				rX->GetNext(&ix, &iy);
+			i = 1;								start = step = 1.0;
+			do {
+				if(data->GetResult(&ares, iy, ix, false)) switch(ares.type) {
+					case ET_TEXT:
+						x_tv->GetValue(ares.text);			break;
+					case ET_VALUE:		case ET_DATE:		case ET_TIME:
+					case ET_DATETIME:	case ET_BOOL:
+						TranslateResult(&ares);
+						x_tv->GetValue(ares.text);			break;
+					}
+				i++;
+				}while(rX->GetNext(&ix, &iy));
+			}
+		if(rX) delete rX;							rX = 0L;
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		if(!(xyPlots = (PlotScatt**)calloc(maxYR, sizeof(PlotScatt*)))){
 			CloseDlgWnd(hDlg);
@@ -5001,32 +5230,53 @@ GroupBars::PropertyDlg()
 		start -= (xinc * ((double)maxYR-1))/2.0;
 		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, desc);
-						CheckBounds(x, y);
-						}
-					x += step;
-					if(!rY->GetNext(&ix, &iy))break;
+			if(mode == 0 && rd) {
+				if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
+				else {
+					rY = 0L;	ny = 0;
+					}
+				}
+			else if(mode == 1 && rdx && rdy) {
+				if(rdx[i] && (rY = new AccRange(rdx[i]))) ny = rY->CountItems();
+				else {
+					rY = 0L;	ny = 0;
+					}
+				}
+			if(rY) {
+				desc = rY->RangeDesc(data, 1);
+				rY->GetFirst(&ix, &iy);
+				if(mode == 1 && (rX = new AccRange(rdy[i]))) {
+					errs = (ErrorBar**)calloc(ny, sizeof(ErrorBar*)); 
+					rX->GetFirst(&ex, &ey);
 					}
-				xyPlots[numXY++] = new PlotScatt(this, data, ic+1, bars);
-				if(xyPlots[i]) {
-					xyPlots[i]->SetSize(SIZE_BARMINX, xinc);
-					xyPlots[i]->SetSize(SIZE_BAR, bw);
-					xyPlots[i]->Command(CMD_BAR_FILL, GetSchemeFill(&sc), 0L);
+				rY->GetNext(&ix, &iy);
+				if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
+					for(ic = 0; ic < ny; ic++) {
+						if(bContinue = data->GetValue(iy, ix, &y)){
+							bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
+								-1, -1, ix, iy, desc);
+							CheckBounds(x, y);
+							}
+						if(errs && rX && rX->GetNext(&ex, &ey) && data->GetValue(ey, ex, &e)) {
+							if(bContinue && (errs[ic] = new ErrorBar(0L, data, x, y, e, 0, -1, -1, ix, iy, ex, ey)))
+								errs[ic]->SetSize(SIZE_ERRBAR, ebw);
+							CheckBounds(x, y+e);	CheckBounds(x, y-e);
+							}
+						x += step;
+						rY->GetNext(&ix, &iy);
+						}
+					xyPlots[numXY++] = new PlotScatt(this, data, ic, bars, errs);
+					if(xyPlots[i]) {
+						xyPlots[i]->SetSize(SIZE_BARMINX, xinc);
+						xyPlots[i]->SetSize(SIZE_BAR, bw);
+						xyPlots[i]->Command(CMD_BAR_FILL, GetSchemeFill(&sc), 0L);
+						}
+					for(ic = 0; ic < ny; ic++) if(bars[ic]) delete(bars[ic]);
+					if(errs) for(ic = 0; ic < ny; ic++) if(errs[ic]) delete(errs[ic]);
+					free(bars);		if(errs) free(errs);	bRet = true;
 					}
-				for(ic = 0; ic < ny; ic++) if(bars[ic]) delete(bars[ic]);
-				free(bars);			bRet = true;
+				delete(rY);		if(desc) free(desc);		rY = 0L;
 				}
-			if(rY) delete(rY);		if(desc) free(desc);		rY = 0L;
 			}
 		}
 	CloseDlgWnd(hDlg);
@@ -5035,7 +5285,15 @@ GroupBars::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
 		free(rd);
 		}
-	if(rY) delete rY;		free(GBDlg);
+	if(rdx) {
+		for (i = 0; i < maxYR; i++)	if(rdx[i]) free(rdx[i]);
+		free(rdx);
+		}
+	if(rdy) {
+		for (i = 0; i < maxYR; i++)	if(rdy[i]) free(rdy[i]);
+		free(rdy);
+		}
+	if(rY) delete rY;		if(rX) delete rX;		free(GBDlg);
 	return bRet;
 }
 
@@ -5196,14 +5454,14 @@ static char *MultiLineDlg_Tmpl =
 	"107,108,,OWNDIALOG,COLBUTT,4,25,87,20,12\n"
 	"108,,,,LTEXT,12,47,90,30,9\n"
 	"200,201,,CHECKED,CHECKBOX,16,25,35,80,9\n"
-	"201,202,,,SYMBUTT,17,25,70,10,10\n"
-	"202,203,,,SYMBUTT,18,37,70,10,10\n"
-	"203,204,,,SYMBUTT,19,49,70,10,10\n"
-	"204,205,,,SYMBUTT,20,61,70,10,10\n"
-	"205,206,,,SYMBUTT,21,73,70,10,10\n"
-	"206,207,,,SYMBUTT,22,85,70,10,10\n"
-	"207,208,,,SYMBUTT,23,97,70,10,10\n"
-	"208,209,,,SYMBUTT,24,109,70,10,10\n"
+	"201,202,,ODEXIT,SYMBUTT,17,25,70,10,10\n"
+	"202,203,,ODEXIT,SYMBUTT,18,37,70,10,10\n"
+	"203,204,,ODEXIT,SYMBUTT,19,49,70,10,10\n"
+	"204,205,,ODEXIT,SYMBUTT,20,61,70,10,10\n"
+	"205,206,,ODEXIT,SYMBUTT,21,73,70,10,10\n"
+	"206,207,,ODEXIT,SYMBUTT,22,85,70,10,10\n"
+	"207,208,,ODEXIT,SYMBUTT,23,97,70,10,10\n"
+	"208,209,,ODEXIT,SYMBUTT,24,109,70,10,10\n"
 	"209,,,CHECKED,CHECKBOX,25,25,50,80,9\n"
 	"300,301,,TOUCHEXIT,RADIO1,13,20,35,80,9\n"
 	"301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
@@ -5371,6 +5629,9 @@ MultiLines::PropertyDlg()
 			updateYR = true;
 			res = -1;
 			break;
+		case 201:	case 202:	case 203:	case 204:
+		case 205:	case 206:	case 207:	case 208:
+			res = -1;
 		case 300:
 			Dlg->SetColor(107, defcol);
 			bContinue = true;
@@ -5396,7 +5657,6 @@ MultiLines::PropertyDlg()
 			res = -1;	break;
 			}
 		}while (res < 0);
-
 	if(res == 1 && rdx && rdy && maxYR) {
 		maxYR++;		rX = rY = 0L;
 		if(xyPlots=(PlotScatt**)calloc(maxYR, sizeof(PlotScatt*))) for(i = numXY = 0; i < maxYR; i++){
@@ -6386,7 +6646,7 @@ FitFunc::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a new normal qualntile plot
+// Create a new normal quantile plot
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char *NormQuantDlg_Tmpl = 
 	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
@@ -7647,36 +7907,39 @@ FitFunc3D::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Grid line properties
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *GridLineDlg_Tmpl =
+	"1,+,,DEFAULT,PUSHBUTTON, 1,150,10,50,12\n"
+	".,.,,,PUSHBUTTON,2,150,25,50,12\n"
+	".,10,,,PUSHBUTTON,-2,150,40,50,12\n"
+	"10,,100,ISPARENT | CHECKED,GROUPBOX,3,5,10,139,123\n"
+	"100,+,,NOSELECT,ODBUTTON,4,10,18,130,100\n"
+	".,.,112,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+	".,.,115,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+	".,.,120,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+	".,.,125,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+	".,,130,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+	"111,,,,RTEXT,5,15,117,23,8\n"
+	"112,+,,,CHECKBOX,-20,41,117,25,8\n"
+	".,.,,,CHECKBOX,-21,105,117,25,8\n"
+	".,111,,,CHECKBOX,-25,70,117,25,8\n"
+	"115,+,,,CHECKBOX,-22,41,117,25,8\n"
+	".,.,,,CHECKBOX,-23,105,117,25,8\n"
+	".,111,,,CHECKBOX,-24,70,117,25,8\n"
+	"120,+,,,CHECKBOX,-24,55,117,25,8\n"
+	".,135,,,CHECKBOX,-25,90,117,25,8\n"
+	"125,+,,,CHECKBOX,-24,55,117,25,8\n"
+	".,135,,,CHECKBOX,-26,90,117,25,8\n"
+	"130,+,,,CHECKBOX,-25,55,117,25,8\n"
+	".,135,,,CHECKBOX,-26,90,117,25,8\n"
+	"135,,,LASTOBJ,LTEXT,6,15,117,55,8";
 bool
 GridLine::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 21, 10, "Line"};
 	int dh = ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL))? -20 : 0;
-	DlgInfo LineDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to AXIS", 150, 25, 50, 12},
-		{3, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
-		{10, 0, 100, ISPARENT | CHECKED, GROUPBOX, (void*)" grid line ", 5, 10, 139, 123+dh},
-		{100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 18, 130, 100},
-		{101, 102, 112, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{102, 103, 115, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{103, 104, 120, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{104, 105, 125, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{105, 0, 130, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{111, 0, 0, 0x0L, RTEXT, (void*)"line to:", 15, 117, 23, 8},
-		{112, 113, 0, 0x0L, CHECKBOX, (void*)"left", 41, 117, 25, 8},
-		{113, 114, 0, 0x0L, CHECKBOX, (void*)"right", 105, 117, 25, 8},
-		{114, 111, 0, 0x0L, CHECKBOX, (void*)"y-axis", 70, 117, 25, 8},
-		{115, 116, 0, 0x0L, CHECKBOX, (void*)"top", 41, 117, 25, 8},
-		{116, 117, 0, 0x0L, CHECKBOX, (void*)"bottom", 105, 117, 25, 8},
-		{117, 111, 0, 0x0L, CHECKBOX, (void*)"x-axis", 70, 117, 25, 8},
-		{120, 121, 0, 0x0L, CHECKBOX, (void*) "x-axis", 55, 117, 25, 8},
-		{121, 135, 0, 0x0L, CHECKBOX, (void*) "y-axis", 90, 117, 25, 8},
-		{125, 126, 0, 0x0L, CHECKBOX, (void*) "x-axis", 55, 117, 25, 8},
-		{126, 135, 0, 0x0L, CHECKBOX, (void*) "z-axis", 90, 117, 25, 8},
-		{130, 131, 0, 0x0L, CHECKBOX, (void*) "y-axis", 55, 117, 25, 8},
-		{131, 135, 0, 0x0L, CHECKBOX, (void*) "z-axis", 90, 117, 25, 8},
-		{135, 0, 0, LASTOBJ, LTEXT, (void*)"parallel to:", 15, 117, 55, 8}};
+	void *dyndata[] = {(void*)"Apply to LINE", (void*)"Apply to AXIS", (void*)" grid line ", 
+		(void*)OD_linedef, (void*)"line to:", (void*)"parallel to:"}; 
+	DlgInfo *LineDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, tmptype;
@@ -7686,10 +7949,12 @@ GridLine::PropertyDlg()
 	LineDEF newLine;
 
 	if(!parent || !parent->parent) return false;
+	if(!(LineDlg = CompileDialog(GridLineDlg_Tmpl, dyndata)))return false;
+	LineDlg[3].h += dh;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
 	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
 	if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
-		//no checkboxes
+		//no checkboxes, changed sizes
 		}
 	else if(flags &AXIS_3D) {
 		Dlg->SetCheck(120, 0L, type & 0x01 ? true : false);
@@ -7714,7 +7979,7 @@ GridLine::PropertyDlg()
 		if(type & 0x07) Dlg->ShowItem(101, true);
 		else Dlg->ShowItem(102, true);
 		}
-	hDlg = CreateDlgWnd("Grid line properties", 50, 50, 415, 300 + dh*2, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Grid line properties", 50, 50, 415, 310 + dh*2, Dlg, 0x0L);
 	do{												//dh*2 means dh * ybase
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -7755,14 +8020,43 @@ GridLine::PropertyDlg()
 			bRet = true;
 			}
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);	delete Dlg;		free(LineDlg);
 	return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Tick properties
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TickDlg_Tmpl =
+	"1,2,,,PUSHBUTTON,1,120,10,60,12\n"
+	"2,3,,DEFAULT, PUSHBUTTON,2,120,25,60,12\n"
+	"3,4,,,PUSHBUTTON,-2,120,40,60,12\n"
+	"4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,110,100\n"
+	"6,7,200,ISPARENT,SHEET,4,5,10,110,100\n"
+	"7,,300,ISPARENT,SHEET,5,5,10,110,100\n"
+	"100,101,,,RTEXT,6,10,30,35,8\n"
+	"101,102,,,EDVAL1,7,50,30,25,10\n"
+	"102,103,,,LTEXT,-3,77,30,20,8\n"
+	"103,104,,,CHECKBOX,8,18,45,30, 8\n"
+	"104,105,,,LTEXT,9,18,60,20,8\n"
+	"105,106,,,RADIO1,0,40,70,35,8\n"
+	"106,107,,,RADIO1,0,40,60,35,8\n"
+	"107,108,,,RADIO1,10,40,80,35,8\n"
+	"108,,,,CHECKBOX,11,18,95,30,8\n"
+	"200,201,,,RTEXT,12,10,35,23,8\n"
+	"201,202,,,EDVAL1,13,40,35,65,10\n"
+	"202,203,,,LTEXT,14,15,55,20,8\n"
+	"203,,,,EDTEXT,0,15,67,90,10\n"
+	"300,301,,,LTEXT,15,15,30,70,8\n"
+	"301,302,,TOUCHEXIT,RADIO1,16,15,42,70,8\n"
+	"302,303,,TOUCHEXIT,RADIO1,17,15,52,70,8\n"
+	"303,304,,TOUCHEXIT,RADIO1,18,15,74,70,8\n"
+	"304,305,,TOUCHEXIT,RADIO1,19,15,84,70,8\n"
+	"305,306,,TOUCHEXIT,RADIO1,20,15,94,70,8\n"
+	"306,307,,, EDVAL1,21,28,62,35,10\n"
+	"307,,,LASTOBJ,LTEXT,22,65,62,20,8";
+
 bool
 Tick::PropertyDlg()
 {
@@ -7770,39 +8064,17 @@ Tick::PropertyDlg()
 	TabSHEET tab2 = {64, 90, 10, "Edit"};
 	TabSHEET tab3 = {25, 64, 10, "Direction"};
 	double tick_rot;
-	DlgInfo TickDlg[] = {
-		{1, 2, 0, 0x0L, PUSHBUTTON, (void*)"Apply to TICK", 100, 10, 50, 12},
-		{2, 3, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to AXIS", 100, 25, 50, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 50, 12},
-		{4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
-		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
-		{7, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"tick size", 10, 30, 35, 8},
-		{101, 102, 0, 0x0L, EDVAL1, &size, 50, 30, 25, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 77, 30, 20, 8},
-		{103, 104, 0, 0x0L, CHECKBOX, (void*)"major tick", 18, 45, 30, 8},
-		{104, 105, 0, 0x0L, LTEXT, (void*)"type:", 18, 60, 20, 8},
-		{105, 106, 0, 0x0L, RADIO1, 0L, 40, 70, 35, 8},
-		{106, 107, 0, 0x0L, RADIO1, 0L, 40, 60, 35, 8},
-		{107, 108, 0, 0x0L, RADIO1, (void*)"symetric", 40, 80, 35, 8},
-		{108, 0, 0, 0x0L, CHECKBOX, (void*)"draw grid line(s)", 18, 95, 30, 8},
-		{200, 201, 0, 0x0L, RTEXT, (void*)"value:", 10, 35, 23, 8},
-		{201, 202, 0, 0x0L, EDVAL1, &value, 40, 35, 35, 10},
-		{202, 203, 0, 0x0L, LTEXT, (void*)"label:", 15, 50, 20, 8},
-		{203, 0, 0, 0x0L, EDTEXT, (void*)0L, 15, 62, 70, 10},
-		{300, 301, 0, 0x0L, LTEXT, (void*)"direction of ticks", 15, 30, 70, 8},
-		{301, 302, 0, TOUCHEXIT, RADIO1, (void*)"perpendicular to axis", 15, 42, 70, 8},
-		{302, 303, 0, TOUCHEXIT, RADIO1, (void*)"fixed angle", 15, 52, 70, 8},
-		{303, 304, 0, TOUCHEXIT, RADIO1, (void*)"x-axis", 15, 74, 70, 8},
-		{304, 305, 0, TOUCHEXIT, RADIO1, (void*)"y-axis", 15, 84, 70, 8},
-		{305, 306, 0, TOUCHEXIT, RADIO1, (void*)"z-axis", 15, 94, 70, 8},
-		{306, 307, 0, 0x0L, EDVAL1, &tick_rot, 28, 62, 35, 10},
-		{307, 0, 0, LASTOBJ, LTEXT, (void*)"degree", 65, 62, 20, 8}};
+	void *dyndata[] = {(void*)"Apply to TICK", (void*)"Apply to AXIS",  (void*)&tab1, (void*)&tab2,
+		(void*)&tab3, (void*)"tick size", (void*)&size, (void*)"major tick", (void*)"type:",
+		(void*)"symmetric", (void*)"draw grid line(s)", (void*)"value:", (void*)&value, (void*)"label:",
+		(void*)"direction of ticks", (void*)"perpendicular to axis", (void*)"fixed angle",
+		(void*)"x-axis", (void*)"y-axis", (void*)"z-axis", (void*)&tick_rot, (void*)"deg."};
+	DlgInfo *TickDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	DWORD old_flags;
-	double new_size, old_size, new_angle, old_angle, new_value, old_value;
+	char old_value[80];
+	double new_size, old_size, new_angle, old_angle, new_value;
 	int res, tmp_type = type;
 	bool bRet = false;
 	DWORD new_flags = flags, undo_flags = 0;
@@ -7811,6 +8083,7 @@ Tick::PropertyDlg()
 	TextDEF *td;
 
 	if(!parent || parent->Id != GO_AXIS) return false;
+	if(!(TickDlg = CompileDialog(TickDlg_Tmpl, dyndata))) return false;
 	switch(type & 0x0f) {
 	case 1:		tick_rot = angle;					break;
 	default:	tick_rot = trig2deg(lsi, lcsi);		break;
@@ -7861,9 +8134,11 @@ Tick::PropertyDlg()
 	else new_size = old_size = size;
 	if(Dlg->GetValue(306, &old_angle)) new_angle = old_angle;
 	else new_angle = old_angle = tick_rot;
-	if(Dlg->GetValue(201, &old_value)) new_value = old_value;
-	else new_value = old_value = value;
-	hDlg = CreateDlgWnd("Tick properties", 50, 50, 315, 260, Dlg, 0x0L);
+	if(flags & AXIS_DATETIME) Dlg->SetText(201, NiceTime(value));
+	if(!(Dlg->GetText(201, old_value, sizeof(old_value)))) {
+		new_value = value;	old_value[0] = 0;
+		}
+	hDlg = CreateDlgWnd("Tick properties", 50, 50, 375, 265, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -7875,7 +8150,6 @@ Tick::PropertyDlg()
 			else new_flags |= AXIS_SYMTICKS;
 			if(Dlg->GetCheck(108)) new_flags |= AXIS_GRIDLINE;
 			Dlg->GetValue(101, &new_size);		Dlg->GetValue(306, &new_angle);
-			Dlg->GetValue(201, &new_value);
 			break;
 		case 301:	case 302:	case 303:	case 304:	case 305:
 			tmp_type = (tmp_type & ~0x0f) | (res -301);
@@ -7890,7 +8164,11 @@ Tick::PropertyDlg()
 		undo_flags = CheckNewInt(&type, type, tmp_type, parent, undo_flags);
 		undo_flags = CheckNewFloat(&size, old_size, new_size, parent, undo_flags);
 		undo_flags = CheckNewFloat(&angle, old_angle, new_angle, parent, undo_flags);
-		undo_flags = CheckNewFloat(&value, old_value, new_value, parent, undo_flags);
+		if(Dlg->GetText(201, TmpTxt, 80) && strcmp(TmpTxt, old_value)) {
+			Undo.ValFloat(parent, &value, undo_flags);		undo_flags |= UNDO_CONTINUE;
+			if(flags & AXIS_DATETIME) date_value(TmpTxt, 0L, &value);
+			else Dlg->GetValue(201, &value);
+			}
 		if(label && label->Id == GO_LABEL) {
 			td = ((Label*)label)->GetTextDef();
 			if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
@@ -7909,8 +8187,7 @@ Tick::PropertyDlg()
 		parent->Command(CMD_REDRAW, 0L, 0L);
 		bRet = true;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(TickDlg);
 	if(old_label) free(old_label);
 	return bRet;
 }
@@ -8663,88 +8940,89 @@ Graph::AddPlot(int family)
 }
 
 static char *GraphDlgTmpl = 
-		"1,2,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
-		"2,3,,,PUSHBUTTON,-2,170,25,45,12\n"
-		"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
-		"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,157,122\n"
-		"5,6,200,ISPARENT,SHEET,2,5,10,157,122\n"
-		"6,7,300,ISPARENT,SHEET,3,5,10,157,122\n"
-		"100,101,,,LTEXT,4,10,25,60,8\n"
-		"101,102,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
-		"102,103,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
-		"103,104,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
-		"104,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
-		"200,201,,,LTEXT,9,10,35,60,8\n"
-		"201,202,,,RTEXT,10,5,47,58,8\n"
-		"202,203,,,EDVAL1,11,64,47,30,10\n"
-		"203,204,,,RTEXT,-5,95,47,10,8\n"
-		"204,205,,,EDVAL1,12,107,47,30,10\n"
-		"205,206,,,LTEXT,-3,140,47,20,8\n"
-		"206,207,,,RTEXT,13,5,59,58,8\n"
-		"207,208,,,EDVAL1,14,64,59,30,10\n"
-		"208,209,,,RTEXT,-5,95,59,10,8\n"
-		"209,210,,,EDVAL1,15,107,59,30,10\n"
-		"210,211,,,LTEXT,-3,140,59,20,8\n"
-		"211,212,,,LTEXT,16,10,84,60,8\n"
-		"212,213,,,RTEXT,17,5,96,58,8\n"
-		"213,214,,,EDVAL1,18,64,96,30,10\n"
-		"214,215,,,RTEXT,-5,95,96,10,8\n"
-		"215,216,,,EDVAL1,19,107,96,30,10\n"
-		"216,217,,,LTEXT,-3,140,96,20,8\n"
-		"217,218,,,RTEXT,20,5,108,58,8\n"
-		"218,219,,,EDVAL1,21,64,108,30,10\n"
-		"219,220,,,RTEXT,-5,95,108,10,8\n"
-		"220,221,,,EDVAL1,22,107,108,30,10\n"
-		"221,,,,LTEXT,-3,140,108,20,8\n"
-		"300,301,,,LTEXT,23,20,30,60,8\n"
-		"301,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
-		"310,311,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
-		"311,312,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
-		"312,313,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
-		"313,314,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
-		"314,315,,EXRADIO,ODBUTTON,24,120,42,25,25\n"
-		"315,316,,CHECKED | TOUCHEXIT,RADIO1, 25, 12,85,40,8\n"
-		"316,317,,TOUCHEXIT,RADIO1,26,12,93,40,8\n"
-		"317,318,,TOUCHEXIT,RADIO1,27,12,101,40,8\n"
-		"318,319,,TOUCHEXIT,CHECKBOX,28,80,85,40,8\n"
-		"319,,,TOUCHEXIT, CHECKBOX,29,80,93,40,8\n"
+		"1,+,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
+		".,.,,,PUSHBUTTON,-2,170,25,45,12\n"
+		".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,157,122\n"
+		".,.,200,ISPARENT,SHEET,2,5,10,157,122\n"
+		".,,300,ISPARENT,SHEET,3,5,10,157,122\n"
+		"100,+,,,LTEXT,4,10,25,60,8\n"
+		".,.,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
+		".,.,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
+		".,.,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
+		".,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
+		"200,+,,,LTEXT,9,10,35,60,8\n"
+		".,.,,,RTEXT,10,5,47,58,8\n"
+		".,.,,,EDVAL1,11,64,47,30,10\n"
+		".,.,,,RTEXT,-5,95,47,10,8\n"
+		".,.,,,EDVAL1,12,107,47,30,10\n"
+		".,.,,,LTEXT,-3,140,47,20,8\n"
+		".,.,,,RTEXT,13,5,59,58,8\n"
+		".,.,,,EDVAL1,14,64,59,30,10\n"
+		".,.,,,RTEXT,-5,95,59,10,8\n"
+		".,.,,,EDVAL1,15,107,59,30,10\n"
+		".,.,,,LTEXT,-3,140,59,20,8\n"
+		".,.,,,LTEXT,16,10,84,60,8\n"
+		".,.,,,RTEXT,17,5,96,58,8\n"
+		".,.,,,EDVAL1,18,64,96,30,10\n"
+		".,.,,,RTEXT,-5,95,96,10,8\n"
+		".,.,,,EDVAL1,19,107,96,30,10\n"
+		".,.,,,LTEXT,-3,140,96,20,8\n"
+		".,.,,,RTEXT,20,5,108,58,8\n"
+		".,.,,,EDVAL1,21,64,108,30,10\n"
+		".,.,,,RTEXT,-5,95,108,10,8\n"
+		".,.,,,EDVAL1,22,107,108,30,10\n"
+		".,,,,LTEXT,-3,140,108,20,8\n"
+		"300,+,,,LTEXT,23,20,30,60,8\n"
+		".,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+		"310,+,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,24,120,42,25,25\n"
+		".,.,,CHECKED | TOUCHEXIT,RADIO1, 25, 12,85,40,8\n"
+		".,.,,TOUCHEXIT,RADIO1,26,12,93,40,8\n"
+		".,.,,TOUCHEXIT,RADIO1,27,12,101,40,8\n"
+		".,.,,TOUCHEXIT,CHECKBOX,28,80,85,40,8\n"
+		".,,,TOUCHEXIT, CHECKBOX,29,80,93,40,8\n"
 		"400,,410,HIDDEN | CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
-		"410,411,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
-		"411,412,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
-		"412,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
-		"500,501,,EXRADIO,ODBUTTON,31,25,60,25,25\n"
-		"501,502,,EXRADIO,ODBUTTON,31,50,60,25,25\n"
-		"502,503,,EXRADIO,ODBUTTON,31,75,60,25,25\n"
-		"503,504,,EXRADIO,ODBUTTON,31,25,85,25,25\n"
-		"504,505,,EXRADIO,ODBUTTON,31,50,85,25,25\n"
-		"505,506,,EXRADIO, ODBUTTON,31,75,85,25,25\n"
-		"506,,,EXRADIO, ODBUTTON,31,100,85,25,25\n"
-		"520,521,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
-		"521,522,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
-		"522,523,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
-		"523,524,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
-		"524,525,,EXRADIO,ODBUTTON,31,120,50,25,25\n"
-		"525,526,,EXRADIO,ODBUTTON,31,20,75,25,25\n"
-		"526,527,,EXRADIO,ODBUTTON,31,45,75,25,25\n"
-		"527,528,,EXRADIO,ODBUTTON,31,70,75,25,25\n"
-		"528,529,,EXRADIO,ODBUTTON,31,95,75,25,25\n"
-		"529,530,,EXRADIO,ODBUTTON,31,120,75,25,25\n"
-		"530,531,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
-		"531,532,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
-		"532,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
-		"540,541,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
-		"541,542,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
-		"542,543,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
-		"543,544,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
-		"544,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
-		"560,561,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
-		"561,562,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
-		"562,563,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
-		"563,564,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
-		"564,565,,EXRADIO,ODBUTTON,31,120,60,25,25\n"
-		"565,566,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
-		"566,567,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
-		"567,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 70,85,25,25";
+		"410,+,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
+		".,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
+		"500,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,95,85,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,120,85,25,25\n"
+		".,,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
+		"520,+,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,120,50,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,20,75,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,75,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,70,75,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,95,75,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,120,75,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
+		".,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
+		"540,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
+		".,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
+		"560,+,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,120,60,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
+		".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
+		".,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 70,85,25,25";
 
 static int selSheet = 102, selPlt = 520, selAxis = 310;
 bool
@@ -8784,7 +9062,7 @@ Graph::PropertyDlg()
 	//restore previous settitings
 	switch(selSheet) {
 		case 101:
-			if(selPlt >= 500 && selPlt <=506) Dlg->SetCheck(selPlt, 0L, true);
+			if(selPlt >= 500 && selPlt <=507) Dlg->SetCheck(selPlt, 0L, true);
 			else Dlg->SetCheck(500, 0L, true);
 			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(540, 0L, true);
 			Dlg->SetCheck(560, 0L, true);		break;
@@ -8865,7 +9143,7 @@ Graph::PropertyDlg()
 			res = -1;
 			break;
 		case 500:	case 501:	case 502:	case 503:
-		case 504:	case 505:	case 506:
+		case 504:	case 505:	case 506:	case 507:
 		case 520:	case 521:	case 522:	case 523:
 		case 524:	case 525:	case 526:	case 527:
 		case 528:	case 529:	case 530:	case 531:	case 532:
@@ -8920,9 +9198,10 @@ Graph::PropertyDlg()
 				else if(Dlg->GetCheck(501))p = new RingChart(this, data);
 				else if(Dlg->GetCheck(502))p = new StarChart(this, data);
 				else if(Dlg->GetCheck(503))p = new BarChart(this, data);
-				else if(Dlg->GetCheck(504))p = new GroupBars(this, data);
+				else if(Dlg->GetCheck(504))p = new GroupBars(this, data, 0);
 				else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
 				else if(Dlg->GetCheck(506))p = new NormQuant(this, data, 0L);
+				else if(Dlg->GetCheck(507))p = new GroupBars(this, data, 1);
 				}
 			else if(Dlg->GetCheck(102)){
 				if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
diff --git a/QT_Spec.h b/QT3_Spec.h
similarity index 70%
copy from QT_Spec.h
copy to QT3_Spec.h
index ac260ae..8dec2a6 100755
--- a/QT_Spec.h
+++ b/QT3_Spec.h
@@ -1,342 +1,290 @@
-//QT_Spec.h, Copyright (c) 2001-2007 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 <qwidget.h>
-#include <qpen.h>
-#include <qpainter.h>
-#include <qprinter.h>
-#include <qmenubar.h>
-#include <qscrollbar.h>
-#include <qdragobject.h>
-#include "TheDialog.h"
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class TxtCurBlink:public QObject {
-	Q_OBJECT
-public:
-	anyOutput *oCopyMark;
-	anyOutput *bmCopyMark;
-
-	TxtCurBlink();
-	void Show();
-	void showCopyMark();
-
-protected:
-	void timerEvent(QTimerEvent *);
-
-private:
-	POINT line[5];
-	bool isVis;
-	int count, cp_mark;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//use sockets for to exchange clipboard data
-#ifdef RLP_PORT
-
-#include <qsocket.h>
-#include <qserversocket.h>
-
-class ReadCB:public QSocket {
-	Q_OBJECT
-public:
-	ReadCB(QObject *parent=0, const char *name=0, GraphObj *g=0);
-	~ReadCB();
-
-private slots:
-	void isConnected();
-	void receiveData();
-	void endData();
-	void isError(int);
-
-private:
-	int level;
-	char *format;
-	QObject *par;
-	GraphObj *DestGO;
-	QString *res;
-};
-
-class RLPsock:public QSocket {
-	Q_OBJECT
-public:
-	RLPsock(int sock, QObject *parent=0, const char *name=0, GraphObj *g=0);
-
-private slots:
-	void readClient();
-
-private:
-	QObject *par;
-	GraphObj *SourceGO;
-};
-
-class RLPserver:public QServerSocket {
-	Q_OBJECT
-public:
-	GraphObj *SourceGO;
-
-	RLPserver(QObject* parent=0, GraphObj *g=0);
-	~RLPserver();
-	void newConnection(int socket){new RLPsock(socket, this, 0, SourceGO);};
-
-	void SetGO(GraphObj *g);
-	char *GetXML();
-	char *GetRLP();
-	char *GetTXT() {return text_plain; };
-
-signals:
-	void newConnect(RLPsock *);
-
-private:
-	char *text_xml, *text_rlp, *text_plain;
-};
-
-#endif //RLP_PORT
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class RLPmenu:public QMenuBar {
-	Q_OBJECT
-public:
-	RLPmenu(QWidget *par, anyOutput *o, GraphObj *g);
-
-public slots:
-	void doMenuItem(int id);
-
-private:
-	anyOutput *OutputClass;
-	QWidget *parent;
-	GraphObj *BaseObj;
-
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The Qt widget class implementet for RLPlot
-class RLPwidget:public QWidget {
-	Q_OBJECT
-
-public:
-	QScrollBar *HScroll, *VScroll;
-	QPixmap *mempic;
-	RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0,
-		GraphObj *g = 0);
-	~RLPwidget();
-
-public slots:
-	void hScrollEvent(int pos);
-	void vScrollEvent(int pos);
-	void cmOpen();
-	void cmSaveData();
-	void cmSaveDataAs();
-	void cmExit();
-	void cmExitRLP();
-	void cmNewGraph();
-	void cmNewPage();
-	void cmDelGraph();
-	void cmAddPlot();
-	void cmAbout();
-	void cmAddRowCol();
-	void cmCopy();
-	void cmCut();
-	void cmPaste();
-	void cmCopyGraph();
-	void cmSaveGraphAs();
-	void cmRedraw();
-	void cmZoom25();
-	void cmZoom50();
-	void cmZoom100();
-	void cmZoom200();
-	void cmZoom400();
-	void cmZoomIn();
-	void cmZoomOut();
-	void cmZoomFit();
-	void cmPrint();
-	void cmExport();
-	void cmDelObj();
-	void cmUpdate();
-	void cmDefaults();
-	void cmAddAxis();
-	void cmAddLegend();
-	void cmLayers();
-	void cmUndo();
-	void cmFillRange();
-	void cmInsRow();
-	void cmInsCol();
-	void cmDelRow();
-	void cmDelCol();
-	void cmtStandard();
-	void cmtDraw();
-	void cmtPolyline();
-	void cmtPolygon();
-	void cmtRectangle();
-	void cmtRoundrect();
-	void cmtEllipse();
-	void cmtArrow();
-	void cmtText();
-	void cmSmplStat();
-	void cmRepCmeans();
-	void cmRepregr();
-	void cmReptwoway();
-	void cmFile1() {openHistoryFile(0);};
-	void cmFile2() {openHistoryFile(1);};
-	void cmFile3() {openHistoryFile(2);};
-	void cmFile4() {openHistoryFile(3);};
-	void cmFile5() {openHistoryFile(4);};
-	void cmFile6() {openHistoryFile(5);};
-
-protected:
-	void paintEvent(QPaintEvent *);
-	void resizeEvent(QResizeEvent *);
-	void closeEvent(QCloseEvent *);
-	void mouseDoubleClickEvent(QMouseEvent *e);
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void keyPressEvent(QKeyEvent *e);
-	void focusInEvent(QFocusEvent *e);
-
-private:
-	QWidget *parent;
-	anyOutput *OutputClass;
-	GraphObj *BaseObj;
-
-	void openHistoryFile(int idx);
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class DlgWidget:public QWidget {
-	Q_OBJECT
-public:
-	QPixmap *mempic;
-	anyOutput *OutputClass;
-
-	DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
-	~DlgWidget();
-
-protected:
-	void paintEvent(QPaintEvent *);
-	void mouseDoubleClickEvent(QMouseEvent *e);
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void keyPressEvent(QKeyEvent *e);
-	void focusInEvent(QFocusEvent *e);
-	void focusOutEvent(QFocusEvent *e);
-	void closeEvent(QCloseEvent *e);
-	void timerEvent(QTimerEvent *);
-
-private:
-	QWidget *parent;
-	tag_DlgObj *dlg;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class BitMapQT:public anyOutput {
-public:
-	QWidget *widget;
-	HatchOut *hgo;
-	QPixmap *mempic;
-	QImage *image;
-	QPen qPen;
-	QPainter qPainter;
-	QFont qFont;
-
-	BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98);
-	BitMapQT(int w, int h, double hr, double vr);
-	~BitMapQT();
-	bool SetLine(LineDEF *lDef);
-	bool SetFill(FillDEF *fill);
-	bool SetTextSpec(TextDEF *set);
-	virtual bool Erase(DWORD Color);
-	virtual bool StartPage() {return true;};
-	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
-		int sw, int sh, bool invert);
-	bool oGetTextExtent(char *text, int cb, int *width, int *height);
-	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
-	bool oGetPix(int x, int y, DWORD *col);
-	bool oDrawIcon(int type, int x, int y);
-	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
-	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSolidLine(POINT *p);
-	bool oTextOut(int x, int y, char *txt, int cb);
-	bool oTextOutW(int x, int y, w_char *txt, int cb);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class OutputQT:public BitMapQT {
-public:
-	QScrollBar *HScroll, *VScroll;
-
-	OutputQT(GraphObj *g);
-	OutputQT(DlgWidget *wi);
-	~OutputQT();
-	bool ActualSize(RECT *rc);
-	void Focus(){if(widget){widget->show(); widget->setActiveWindow();widget->raise();}};
-	void Caption(char *txt);
-	void MouseCursor(int cid, bool force);
-	bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
-	bool EndPage();
-	bool UpdateRect(RECT *rc, bool invert);
-	void ShowBitmap(int x, int y, anyOutput* src);
-	void ShowLine(POINT * pts, int cp, DWORD color);
-	void ShowEllipse(POINT p1, POINT p2, DWORD color); 
-	bool SetMenu(int type);
-	void CheckMenu(int mid, bool check);
-	void FileHistory();
-	void CreateNewWindow(GraphObj *g);
-
-private:
-	GraphObj *BaseObj;
-	RLPmenu *menu;
-};
-
-class PrintQT:public anyOutput{
-public:
-	HatchOut *hgo;
-	QPrinter *printer;
-
-	PrintQT(GraphObj *g, char *file);
-	~PrintQT();
-	bool ActualSize(RECT *rc);
-	bool SetLine(LineDEF *lDef);
-	bool SetFill(FillDEF *fill);
-	bool SetTextSpec(TextDEF *set);
-	bool StartPage();
-	bool EndPage();
-	bool Eject();
-	bool oGetTextExtent(char *text, int cb, int *width, int *height);
-	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
-	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
-	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSolidLine(POINT *p);
-	bool oTextOut(int x, int y, char *txt, int cb);
-	bool oTextOutW(int x, int y, w_char *txt, int cb);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-
-private:
-	QPen qPen;
-	QFont qFont;
-	QPainter qPainter;
-	QWMatrix dxf;
-	char *fileName;
-	GraphObj *go;
-	bool bPrinting;
-};
+//QT_Spec.h, Copyright (c) 2001-2007 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 "menu.h"
+#include <qapplication.h>
+#include <qwidget.h>
+#include <qstring.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <qprinter.h>
+#include <qmenubar.h>
+#include <qscrollbar.h>
+#include <qcstring.h>
+#include <qpaintdevicemetrics.h>
+#include <qpen.h>
+#include <qprinter.h>
+#include <qdragobject.h>
+#include <qmenubar.h>
+#include <qscrollbar.h>
+#include <qmessagebox.h>
+#include <qpixmap.h>
+#include <qfiledialog.h>
+#include <qimage.h>
+#include <qcursor.h>
+#include <qclipboard.h>
+#include <qbuffer.h>
+#include <qbitmap.h>
+#include <qtextstream.h>
+#include <qdragobject.h>
+#include "TheDialog.h"
+
+#define RLP_PORT	4321		//enable clipboard server
+#ifdef RLP_PORT
+	#include <sys/socket.h>
+	#include <netdb.h>
+	#include <pthread.h>
+	#include <fcntl.h>
+	#include <unistd.h>
+	#include <sys/ioctl.h>
+	#include <linux/fs.h> 
+#endif
+
+bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj);
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class TxtCurBlink:public QObject {
+	Q_OBJECT
+public:
+	TxtCurBlink();
+	void Show();
+//	void showCopyMark();
+
+protected:
+	void timerEvent(QTimerEvent *);
+
+private:
+	bool isVis;
+	int count;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use sockets for to exchange clipboard data
+// undefine RLP_PORT to limit clipboard to a single instance
+
+class RLPserver {
+public:
+	GraphObj *SourceGO;
+
+	RLPserver(QObject* parent=0, GraphObj *g=0);
+	~RLPserver();
+
+	void SetGO(GraphObj *g);
+	char *GetXML();
+	char *GetRLP();
+	char *GetTXT() {return text_plain; };
+	bool ok() {return true;};
+#ifdef RLP_PORT
+	int Socket() {return sock;};
+#endif
+
+private:
+	char *text_xml, *text_rlp, *text_plain;
+#ifdef RLP_PORT
+	pthread_t thread;
+	pthread_attr_t thread_attr;
+	int sock;
+#endif
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class RLPmenu:public QMenuBar {
+	Q_OBJECT
+public:
+	RLPmenu(QWidget *par, anyOutput *o, GraphObj *g);
+
+public slots:
+	void doMenuItem(int id);
+
+private:
+	anyOutput *OutputClass;
+	QWidget *parent;
+	GraphObj *BaseObj;
+
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The Qt widget class implementet for RLPlot
+class RLPwidget:public QWidget {
+	Q_OBJECT
+
+public:
+	QScrollBar *HScroll, *VScroll;
+	QPixmap *mempic;
+	QMenuBar *menu_bar;
+
+	RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0,
+		GraphObj *g = 0);
+	~RLPwidget();
+	void openHistoryFile(int idx);
+
+public slots:
+	void hScrollEvent(int pos);
+	void vScrollEvent(int pos);
+	void cmNOP(){;};
+	void cmCopy(){ProcMenuEvent(CM_COPY, this, OutputClass, BaseObj);};
+	void cmCut(){ProcMenuEvent(CM_CUT, this, OutputClass, BaseObj);};
+	void cmZoomIn(){ProcMenuEvent(CM_ZOOMIN, this, OutputClass, BaseObj);};
+	void cmZoomOut(){ProcMenuEvent(CM_ZOOMOUT, this, OutputClass, BaseObj);};
+	void cmZoomFit(){ProcMenuEvent(CM_ZOOMFIT, this, OutputClass, BaseObj);};
+	void cmPaste();
+	void cmUndo(){if(BaseObj) BaseObj->Command(CMD_UNDO, 0L, OutputClass);};
+
+protected:
+	void paintEvent(QPaintEvent *);
+	void resizeEvent(QResizeEvent *);
+	void closeEvent(QCloseEvent *);
+	void mouseDoubleClickEvent(QMouseEvent *e);
+	void mousePressEvent(QMouseEvent *e);
+	void mouseReleaseEvent(QMouseEvent *e);
+	void mouseMoveEvent(QMouseEvent *e);
+	void keyPressEvent(QKeyEvent *e);
+	void focusInEvent(QFocusEvent *e);
+
+private:
+	QWidget *parent;
+	anyOutput *OutputClass;
+	GraphObj *BaseObj;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class DlgWidget:public QWidget {
+	Q_OBJECT
+public:
+	QPixmap *mempic;
+	anyOutput *OutputClass;
+
+	DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
+	~DlgWidget();
+
+protected:
+	void paintEvent(QPaintEvent *);
+	void mouseDoubleClickEvent(QMouseEvent *e);
+	void mousePressEvent(QMouseEvent *e);
+	void mouseReleaseEvent(QMouseEvent *e);
+	void mouseMoveEvent(QMouseEvent *e);
+	void keyPressEvent(QKeyEvent *e);
+	void focusInEvent(QFocusEvent *e);
+	void focusOutEvent(QFocusEvent *e);
+	void closeEvent(QCloseEvent *e);
+	void timerEvent(QTimerEvent *);
+
+private:
+	QWidget *parent;
+	tag_DlgObj *dlg;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class BitMapQT:public anyOutput {
+public:
+	QWidget *widget;
+	QWidget *dlgwidget;
+	HatchOut *hgo;
+	QPixmap *mempic;
+	QImage *image;
+	QPen qPen;
+	QPainter qPainter;
+	QFont qFont;
+	void *ShowObj;				//eph_obj*
+	void *ShowAnimated;			//copy mark
+
+	BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98);
+	BitMapQT(int w, int h, double hr, double vr);
+	~BitMapQT();
+	bool SetLine(LineDEF *lDef);
+	bool SetFill(FillDEF *fill);
+	bool SetTextSpec(TextDEF *set);
+	virtual bool Erase(DWORD Color);
+	virtual bool StartPage() {return true;};
+	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+		int sw, int sh, bool invert);
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
+	bool oGetPix(int x, int y, DWORD *col);
+	bool oDrawIcon(int type, int x, int y);
+	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oSolidLine(POINT *p);
+	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
+	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class OutputQT:public BitMapQT {
+public:
+	QScrollBar *HScroll, *VScroll;
+	RLPmenu *menu;
+
+	OutputQT(GraphObj *g);
+	OutputQT(DlgWidget *wi);
+	~OutputQT();
+	bool ActualSize(RECT *rc);
+	void Focus(){if(widget){widget->show(); widget->raise();}};
+	void Caption(char *txt);
+	void MouseCursor(int cid, bool force);
+	bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
+	bool EndPage();
+	bool UpdateRect(RECT *rc, bool invert);
+	void ShowLine(POINT * pts, int cp, DWORD color);
+	void ShowEllipse(POINT p1, POINT p2, DWORD color); 
+	bool SetMenu(int type);
+	void CheckMenu(int mid, bool check);
+	void FileHistory();
+	void CreateNewWindow(GraphObj *g);
+
+private:
+	GraphObj *BaseObj;
+};
+
+class PrintQT:public anyOutput{
+public:
+	HatchOut *hgo;
+	QPrinter *printer;
+
+	PrintQT(GraphObj *g, char *file);
+	~PrintQT();
+	bool ActualSize(RECT *rc);
+	bool SetLine(LineDEF *lDef);
+	bool SetFill(FillDEF *fill);
+	bool SetTextSpec(TextDEF *set);
+	bool StartPage();
+	bool EndPage();
+	bool Eject();
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
+	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oSolidLine(POINT *p);
+	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
+	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+	QPen qPen;
+	QFont qFont;
+	QPainter qPainter;
+	QWMatrix dxf;
+	char *fileName;
+	GraphObj *go;
+	bool bPrinting;
+};
+
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index dbee7a8..391157e 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -1,3273 +1,4045 @@
-//QT_Spec.cpp, Copyright (c) 2001-2007 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 "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 UndoObj Undo;
-
-QApplication *QAppl;
-QWidget *MainWidget =0L, *CurrWidget = 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) {
-		if(!qf.selectedFile().isEmpty()) {
-			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)
-{
-	QFileDialog qf(0,0,true);
-	QString filters("RLPlot files (*.rlp)");
-	int i, cb;
-	char *ext;
-
-	qf.setFilters(filters);				qf.setDir(defs.currPath);
-	qf.setSelection(oldname);			qf.setMode(QFileDialog::AnyFile);
-	if(qf.exec() == QDialog::Accepted) {
-		if(!qf.selectedFile().isEmpty()) {
-			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 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-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)
-{
-	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, cb;
-
-	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;
-	case 1:		return 0;
-	default:	return 2;
-		}
-	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,  bSuspend = 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;			bSuspend = false;
-	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;	bSuspend = false;
-	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);
-		}
-	if(cTxtCur->bmCopyMark) delete(cTxtCur->bmCopyMark);
-	cTxtCur->bmCopyMark = new BitMapQT(rCopyMark.right - rCopyMark.left+1, 
-		rCopyMark.bottom - rCopyMark.top+1, out->hres, out->vres);
-}
-
-void InvalidateOutput(anyOutput *o)
-{
-	if(!o || !cTxtCur) return;
-	if(o == cTxtCur->oCopyMark) {
-		cTxtCur->oCopyMark = 0L;
-		if(cTxtCur->bmCopyMark) delete cTxtCur->bmCopyMark;
-		cTxtCur->bmCopyMark = 0L;
-		}
-	if(o == oTxtCur) {
-		oTxtCur = 0L;	bTxtCur = false;
-		}
-}
-
-void SuspendAnimation(anyOutput *o, bool bSusp)
-{
-	if(!o || !cTxtCur) return;
-	if(!bSusp) bSuspend = false;
-	else {
-		if(o == cTxtCur->oCopyMark) bSuspend = bSusp;
-		if(o == oTxtCur) bSuspend = bSusp;
-		}
-}
-
-LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
-LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
-
-TxtCurBlink::TxtCurBlink():QObject(CurrWidget, 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)
-{
-	if(bSuspend) return;		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
-// code based on Qt example code
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#define MIME_KSPREAD "application/x-kspread-snippet"
-
-#ifdef RLP_PORT
-static RLPserver *rlpsrv = 0L;
-
-ReadCB::ReadCB(QObject *parent, const char *name, GraphObj *g):QSocket(parent, name)
-{
-	par = parent;	DestGO = g;		res= 0L;	level = 0;	format = 0L;
-	connect(this, SIGNAL(connected()), SLOT(isConnected()));
-	connect(this, SIGNAL(readyRead()), SLOT(receiveData()));
-	connect(this, SIGNAL(connectionClosed()), SLOT(endData()));
-	connect(this, SIGNAL(error(int)), SLOT(isError(int)));
-	connectToHost("localhost", RLP_PORT);
-}
-
-ReadCB::~ReadCB()
-{
-	if(res) delete res;			res= 0L;
-	if(format) free(format);	format = 0L;
-}
-
-void
-ReadCB::isConnected()
-{
-	QTextStream ts(this);
-	ts << "enum formats\n";
-	res = new QString();
-}
-
-void
-ReadCB::receiveData()
-{
-	char *line;
-
-	QTextStream ts(this);
-	if(!level) while(canReadLine()){
-		QString s = ts.readLine();
-		if(DestGO && (DestGO->Id == GO_SPREADDATA || DestGO->Id == GO_PAGE || DestGO->Id == GO_GRAPH)) {
-			if(s == "text/xml" || s == "text/rlp-graph" || s == "text/rlp-page") {
-				while(bytesAvailable()) getch();
-				format = strdup(s.ascii());				level = 1;
-				ts << "get " << s << "\n";
-				}
-			}
-		}
-	else while(canReadLine()) {
-		res->append(ts.readLine());
-		res->append("\n");
-		}
-}
-
-void
-ReadCB::endData()
-{
-	receiveData();
-	if(res && res->length() > 5 && DestGO && DestGO->Id == GO_SPREADDATA) {
-		if(strcmp(format, "text/xml") == 0) DestGO->Command(CMD_PASTE_XML, (void*)res->ascii(), 0L);
-		if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
-		if(strcmp(format, "text/rlp-page") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
-		}
-	else if(res && res->length() > 5 && DestGO && (DestGO->Id == GO_PAGE || DestGO->Id == GO_GRAPH)) {
-		if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
-		if(strcmp(format, "text/rlp-page") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
-		}
-	if(res) delete res;		res= 0L;
-	delete this;
-}
-
-void
-ReadCB::isError(int)
-{
-	QClipboard *cb;
-	QDragObject *mime;
-
-	if((cb = QAppl->clipboard()) && (mime = (QDragObject *)cb->data())) {
-		if(DestGO && DestGO->Id == GO_SPREADDATA) {
-			if(mime->provides(MIME_KSPREAD)){
-				QByteArray b = mime->encodedData(MIME_KSPREAD);
-				if(b) DestGO->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
-				delete this;	return;
-				}
-			else if(mime->provides("text/plain")){
-				ProcMemData(DestGO, (unsigned char*)cb->text().latin1(), true);
-				delete this;	return;
-				}
-			}
-		}
-	delete this;
-}
-
-RLPsock::RLPsock(int sock, QObject *parent, const char *name, GraphObj *g):QSocket(parent, name)
-{
-	par = parent;	SourceGO = g;
-	connect(this, SIGNAL(readyRead()), SLOT(readClient()));
-	connect(this, SIGNAL(connectionClosed()), SLOT(deleteLater()));
-	setSocket(sock);
-}
-
-void
-RLPsock::readClient()
-{
-	char *ptr = 0L;
-	const char *cmd;
-
-	//allow only connetions from local host
-	/*
-	if(peerAddress().toString() != "127.0.0.1") {close(); return;}
-	*/
-	QTextStream ts(this);
-	while(canReadLine()) {
-		QString str = ts.readLine();
-		cmd = str.ascii();
-		if(strcmp(cmd, "close") == 0) {
-			close();
-			if(rlpsrv && par) delete par;
-			return;
-			}
-		else if(strcmp(cmd, "exit") == 0) {
-			close();
-			if(rlpsrv && par) delete par;
-			return;
-			}
-		else if(strcmp(cmd, "enum formats") == 0) {
-			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
-				ts << "text/xml\n";
-				if(((RLPserver*)par)->GetTXT()) ts << "text/plain\n";
-				}
-			else if(SourceGO && SourceGO->Id == GO_GRAPH) ts << "text/rlp-graph\n";
-			else if(SourceGO && SourceGO->Id == GO_PAGE) ts << "text/rlp-page\n";
-			else close();
-			}
-		else if(strcmp(cmd, "get text/xml") == 0) {
-			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
-				if(ptr = ((RLPserver*)par)->GetXML()) ts << ptr;
-				}
-			close();
-			}
-		else if(strcmp(cmd, "get text/rlp-graph") == 0 || strcmp(cmd, "get text/rlp-page") == 0) {
-			if(SourceGO && (SourceGO->Id == GO_GRAPH || SourceGO->Id == GO_PAGE)) {
-				if(ptr = ((RLPserver*)par)->GetRLP()) ts << ptr;
-				}
-			close();
-			}
-		else if(strcmp(cmd, "get text/plain") == 0) {
-			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
-				if(ptr = ((RLPserver*)par)->GetTXT()) ts << ptr;
-				}
-			close();
-			}
-		else close();
-		}
-}
-
-
-RLPserver::RLPserver(QObject* parent, GraphObj *g):QServerSocket(RLP_PORT, 4, parent)
-{
-	text_xml = text_rlp = text_plain = 0L;
-	SetGO(g);
-}
-
-RLPserver::~RLPserver()
-{
-	rlpsrv = 0L;
-	HideCopyMark();
-	if(text_xml) free(text_xml);		text_xml =  0L;
-	if(text_rlp) free(text_rlp);		text_rlp =  0L;
-	if(text_plain) free(text_plain);	text_plain = 0L;
-}
-
-void 
-RLPserver::SetGO(GraphObj *g)
-{
-	QClipboard *cb;
-
-	SourceGO = g;
-	if(text_xml) free(text_xml);		text_xml =  0L;
-	if(text_rlp) free(text_rlp);		text_rlp =  0L;
-	if(text_plain) free(text_plain);	text_plain = 0L;
-	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
-		SourceGO->Command(CMD_COPY_TSV, &text_plain, 0L);
-		if(text_plain && text_plain[0]){
-			cb = QAppl->clipboard();
-			cb->clear();
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-			cb->setText(text_plain, QClipboard::Clipboard);
-			cb->setText(text_plain, QClipboard::Selection);
-#else
-			cb->setText(text_plain);
-#endif
-			}
-		}
-}
-
-char *
-RLPserver::GetXML()
-{
-	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
-		if(!text_xml) SourceGO->Command(CMD_COPY_XML, &text_xml, 0L);
-		return text_xml;
-		}
-	return 0L;
-}
-
-char *
-RLPserver::GetRLP()
-{
-	long cb;
-
-	if(SourceGO && (SourceGO->Id == GO_GRAPH || SourceGO->Id == GO_PAGE)) {
-		text_rlp = GraphToMem(SourceGO, &cb);
-		return text_rlp;
-		}
-	return 0L;
-}
-
-#endif //RLP_PORT
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Process paste command: check for clipboard contents
-void TestClipboard(GraphObj *g)
-{
-	if(!g) return;
-#ifdef RLP_PORT
-	if(rlpsrv && rlpsrv->SourceGO) {
-		if(rlpsrv->SourceGO->Id == GO_GRAPH || rlpsrv->SourceGO->Id == GO_PAGE)
-			OpenGraph(g, 0L, (unsigned char*)rlpsrv->GetRLP(), true);
-		else if(rlpsrv->SourceGO->Id == GO_SPREADDATA && g->Id == GO_SPREADDATA)
-			g->Command(CMD_PASTE_XML, (void*)rlpsrv->GetXML(), 0L);
-		}
-	else new ReadCB(0, 0, g);
-#endif //RLP_PORT
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Copy spreadsheet or graph to clipboard
-void CopyData(GraphObj *g)
-{
-	HideCopyMark();
-	QAppl->clipboard()->clear();
-#ifdef RLP_PORT
-	if(rlpsrv) {
-		if(rlpsrv->ok()) rlpsrv->SetGO(g);
-		else {
-			delete rlpsrv;
-			rlpsrv = new RLPserver(0, g);
-			}
-		}
-	else rlpsrv = new RLPserver(0, g);
-#endif //RLP_PORT
-}
-
-void CopyGraph(GraphObj *g)
-{
-	if(g->Id == GO_PAGE && CurrGraph) CopyData(CurrGraph);
-	else CopyData(g);
-}
-
-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();
-//		}
-#endif //RLP_PORT
-	HideCopyMark();
-	QAppl->clipboard()->clear();
-}
-
-void CopyText(char *txt, int len)
-{
-	QClipboard *cb;
-
-	if(!(cb = QAppl->clipboard()) || !txt || !txt[0]) return;
-	EmptyClip();
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-	cb->setText(txt, QClipboard::Clipboard);
-	cb->setText(txt, QClipboard::Selection);
-#else
-	cb->setText(txt);
-#endif
-}
-
-unsigned char* PasteText()
-{
-	QClipboard *cb;
-	QMimeSource *mime;
-	unsigned char *tmp_txt = 0L;
-
-	if(!(cb = QAppl->clipboard())) return 0L;
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-	QString qstr = cb->text(QClipboard::Clipboard);
-#else
-	QString qstr = cb->text();
-#endif
-	if(qstr.length()) tmp_txt = (unsigned char*) strdup(qstr);
-	else {
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-		qstr = cb->text(QClipboard::Selection);
-#else
-		QString qstr = cb->text();
-#endif
-		if(qstr.length()) tmp_txt = (unsigned char*) strdup(qstr);
-		}
-	return tmp_txt;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get display (desktop) size
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void GetDesktopSize(int *width, int *height)
-{
-	QWidget *d = QApplication::desktop();
-	*width = d->width();
-	*height = d->height();
-	if(*width < 800 || *height < 600){
-		*width = 800;		*height = 600;
-		}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool com_QStringExt(QString txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
-{
-	QRect rc;
-
-	if(cb >0)txt.truncate(cb);
-	rc = qP->boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, txt);
-	*width = rc.rRight() - rc.rLeft();
-	*height = TxtSet->iSize +2;
-	return true;
-}
-
-bool
-com_GetTextExtent(char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
-{
-	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
-	else return com_QStringExt(QString(txt), width, height, cb > 0 ? cb : (int)strlen(txt), TxtSet, qP);
-}
-
-bool
-com_GetTextExtentW(w_char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
-{
-	int i;
-	QString wtxt(0);
-
-	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
-	for(i = 0; txt[i] && i < cb; i++) wtxt.append(QChar(txt[i]));
-	com_QStringExt(wtxt, width, height, cb, TxtSet, qP);
-}
-
-bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
-{
-	int i, w, h, ix, iy;
-	QBrush oldBrush;
-	QPen oldPen, currPen;
-	QWMatrix xf, dxf;
-
-	if(!TxtSet->iSize && TxtSet->fSize > 0.0) TxtSet->iSize = o->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);
-	oldBrush = qP->brush();						dxf = qP->worldMatrix();
-	oldPen = currPen = qP->pen();				iy = y;
-	com_QStringExt(txt, &w, &h, -1, TxtSet, qP);
-	if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1);
-	else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
-	else ix = x;
-	currPen.setColor(SwapRB(TxtSet->ColTxt));
-	qP->setPen(currPen);
-	if(fabs(TxtSet->RotBL) >.01 || fabs(TxtSet->RotCHAR) >.01) {
-		xf.translate(x, y);
-		xf.rotate(-TxtSet->RotBL);
-		qP->setWorldMatrix(xf, TRUE);
-		if(TxtSet->Mode == TXM_OPAQUE){
-			currPen.setColor(SwapRB(TxtSet->ColBg));
-			qP->setPen(currPen);
-			qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
-			qP->drawRect(0, - iround(h*.8), w, h);
-			currPen.setColor(SwapRB(TxtSet->ColTxt));
-			qP->setPen(currPen);
-			}
-		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 {
-		if(TxtSet->Mode == TXM_OPAQUE){
-			currPen.setColor(SwapRB(TxtSet->ColBg));
-			qP->setPen(currPen);
-			qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
-			qP->drawRect(ix, iy - iround(h*.8), w, h);
-			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);
-		qP->drawText(ix, iy, txt, -1);
-		}
-	oldPen.setCapStyle(Qt::RoundCap);
-	oldPen.setJoinStyle(Qt::RoundJoin);
-	qP->setPen(oldPen);
-	qP->setBrush(oldBrush);
-	qP->setWorldMatrix(dxf, FALSE);
-	return true;
-}
-
-bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
-{
-	int i, w, h, ix, iy;
-	QString txt(ctxt);
-
-	if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false;
-	if(TxtSet->Font==FONT_GREEK) {
-		txt.truncate(0);
-		for(i = 0; ctxt[i]; i++) {
-			if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391));
-			else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1));
-			else txt.append(QChar(ctxt[i]));
-			}
-		}
-	return com_QStringOut(x, y, txt, TxtSet, qP, o);
-}
-
-bool com_TextOutW(int x, int y, w_char *wtxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
-{
-	int i;
-	QString txt(0);
-
-	if(!wtxt || !wtxt[0] || !TxtSet || !qP || !o) return false;
-	for(i = 0; wtxt[i]; i++) txt.append(QChar(wtxt[i]));
-	return com_QStringOut(x, y, txt, TxtSet, qP, o);
-}
-
-bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP)
-{
-	bool RetVal;
-
-	if(!set->iSize && set->fSize > 0.0) set->iSize = o->un2iy(set->fSize);
-	if(!set->iSize) return false;
-	RetVal = o->anyOutput::SetTextSpec(set);
-	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((TxtSet->iSize > 1) ? (int)(TxtSet->iSize*0.71) : 1);
-		else qF.setPointSize((TxtSet->iSize > 2) ? TxtSet->iSize : 2);
-		switch(TxtSet->Font){
-		case FONT_HELVETICA:
-		default:			qF.setFamily("Helvetica");			break;
-		case FONT_GREEK:
-		case FONT_TIMES:	qF.setFamily("Times");				break;
-		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[]={
-/* width height ncolors chars_per_pixel */
-"32 32 169 2",
-/* colors */
-"AA c #FFFFFFFFFFFF",
-"BA c #FFFFF7F79494",
-"CA c #FFFFF7F78484",
-"DA c #FFFFF7F77373",
-"EA c #FFFFF7F75252",
-"FA c #FFFFF7F74242",
-"GA c #FFFFF7F73939",
-"HA c #FFFFEFEF8C8C",
-"IA c #FFFFEFEF4A4A",
-"JA c #FFFFEFEF2929",
-"KA c #F7F7E7E77B7B",
-"LA c #F7F7C6C6ADAD",
-"MA c #F7F7B5B59C9C",
-"NA c #F7F7ADAD9494",
-"OA c #EFEFF7F7F7F7",
-"PA c #EFEFF7F7EFEF",
-"AB c #EFEFEFEFEFEF",
-"BB c #EFEFEFEFDEDE",
-"CB c #EFEFE7E7A5A5",
-"DB c #EFEFDEDE7373",
-"EB c #EFEFDEDE3939",
-"FB c #EFEFDEDE2929",
-"GB c #EFEFD6D64242",
-"HB c #EFEFA5A58C8C",
-"IB c #EFEF94947B7B",
-"JB c #EFEF84847373",
-"KB c #EFEF84846363",
-"LB c #EFEF7B7B7373",
-"MB c #E7E7E7E7CECE",
-"NB c #E7E7E7E79494",
-"OB c #E7E7DEDE6B6B",
-"PB c #E7E7DEDE5252",
-"AC c #E7E7CECE5252",
-"BC c #E7E77B7B6363",
-"CC c #E7E773735A5A",
-"DC c #E7E76B6B5252",
-"EC c #E7E75A5A4A4A",
-"FC c #DEDEE7E7F7F7",
-"GC c #DEDEE7E7EFEF",
-"HC c #DEDEDEDEDEDE",
-"IC c #DEDEDEDEBDBD",
-"JC c #DEDECECE4A4A",
-"KC c #DEDE4A4A3939",
-"LC c #D6D6EFEFCECE",
-"MC c #D6D6DEDEEFEF",
-"NC c #D6D6DEDECECE",
-"OC c #CECEDEDEDEDE",
-"PC c #CECED6D6CECE",
-"AD c #CECECECEB5B5",
-"BD c #CECECECE5A5A",
-"CD c #C6C6E7E7C6C6",
-"DD c #C6C6DEDEEFEF",
-"ED c #C6C6D6D67373",
-"FD c #C6C6CECE4A4A",
-"GD c #BDBDDEDEB5B5",
-"HD c #BDBDCECEE7E7",
-"ID c #BDBDCECECECE",
-"JD c #BDBDC6C6D6D6",
-"KD c #BDBD39394242",
-"LD c #B5B5DEDEADAD",
-"MD c #B5B5BDBDCECE",
-"ND c #B5B5BDBD4242",
-"OD c #B5B5B5B59C9C",
-"PD c #ADADD6D6ADAD",
-"AE c #ADADCECEDEDE",
-"BE c #ADADBDBDB5B5",
-"CE c #ADADB5B54242",
-"DE c #ADAD4A4A5252",
-"EE c #A5A5BDBDDEDE",
-"FE c #A5A5BDBDCECE",
-"GE c #A5A5ADADB5B5",
-"HE c #A5A5ADAD4242",
-"IE c #A5A563637B7B",
-"JE c #9C9CD6D6A5A5",
-"KE c #9C9CBDBDD6D6",
-"LE c #9C9CBDBDBDBD",
-"ME c #9C9CADADCECE",
-"NE c #9C9CADADA5A5",
-"OE c #9C9C52525252",
-"PE c #9C9C4A4A5252",
-"AF c #9494CECE9C9C",
-"BF c #9494B5B5CECE",
-"CF c #9494ADAD5A5A",
-"DF c #9494ADAD3939",
-"EF c #8C8CCECE9494",
-"FF c #8C8CCECE8C8C",
-"GF c #8C8CB5B5B5B5",
-"HF c #8C8CADADD6D6",
-"IF c #8C8CADADCECE",
-"JF c #8C8CADADB5B5",
-"KF c #8C8CADADA5A5",
-"LF c #8C8C9C9CB5B5",
-"MF c #8C8C9C9CADAD",
-"NF c #8C8C8C8CA5A5",
-"OF c #8C8C52526363",
-"PF c #8C8C42425252",
-"AG c #8484B5B5CECE",
-"BG c #7B7BCECE9494",
-"CG c #7B7BC6C68484",
-"DG c #7B7BC6C67B7B",
-"EG c #7B7BADADC6C6",
-"FG c #7B7BADADADAD",
-"GG c #7B7B9C9CC6C6",
-"HG c #7B7B9C9CB5B5",
-"IG c #7B7B9C9CADAD",
-"JG c #7B7B84849C9C",
-"KG c #7B7B42425252",
-"LG c #737384848C8C",
-"MG c #737373738484",
-"NG c #737339395252",
-"OG c #6B6BC6C68484",
-"PG c #6B6BBDBD7B7B",
-"AH c #6B6BA5A5CECE",
-"BH c #6B6B9C9CBDBD",
-"CH c #6B6B9C9CA5A5",
-"DH c #6B6B94949C9C",
-"EH c #6B6B8C8CA5A5",
-"FH c #6B6B8C8C9C9C",
-"GH c #6B6B6B6B7B7B",
-"HH c #6B6B42425252",
-"IH c #6363BDBD6B6B",
-"JH c #6363B5B58C8C",
-"KH c #6363A5A58C8C",
-"LH c #63639C9CC6C6",
-"MH c #5A5AB5B56363",
-"NH c #5A5A9C9CBDBD",
-"OH c #5A5A8C8C9C9C",
-"PH c #5A5A7B7B8C8C",
-"AI c #5A5A6B6B8484",
-"BI c #5A5A63637B7B",
-"CI c #5252BDBD7373",
-"DI c #5252ADAD8484",
-"EI c #5252A5A57B7B",
-"FI c #4A4AB5B55A5A",
-"GI c #4A4A8C8CBDBD",
-"HI c #4A4A8C8CADAD",
-"II c #4A4A7B7B9C9C",
-"JI c #4A4A7B7B8484",
-"KI c #4A4A6B6B7B7B",
-"LI c #42429C9C7373",
-"MI c #42428C8C7B7B",
-"NI c #42425A5A7373",
-"OI c #42424A4A6B6B",
-"PI c #3939ADAD6B6B",
-"AJ c #3939ADAD5A5A",
-"BJ c #39399C9C6B6B",
-"CJ c #39398484BDBD",
-"DJ c #39397B7BADAD",
-"EJ c #39397B7B8C8C",
-"FJ c #393973737B7B",
-"GJ c #313163637B7B",
-"HJ c #31315A5A7B7B",
-"IJ c #292984846B6B",
-"JJ c #29296B6B7B7B",
-"KJ c #21217B7BB5B5",
-"LJ c #21217373A5A5",
-"MJ c #212173739C9C",
-"NJ c #21216B6B8C8C",
-"OJ c #212152527373",
-"PJ c #181884846363",
-"AK c #18186B6B7B7B",
-"BK c #18185A5A7373",
-"CK c #10106B6B9C9C",
-"DK c #10105A5A8484",
-"EK c #08087B7B6363",
-"FK c #08085A5A7B7B",
-"GK c #00006B6B9C9C",
-"HK c #000063637B7B",
-"IK c #00005A5A8C8C",
-/* pixels */
-"CJAHAHAHAHHILHLHBHLHLJNHNHNHGINHGINHGINHGINHGINHGINHGINHGINHGIKJ",
-"AHAAAAAAAGHDABBBGCBFBFHCPCOCEEHDJDEEJDEEHDJDEEHDJDEEJDEEHDEEJDNH",
-"AHAAAGAAABABABKEOCHCHCPCFEFEABAEHDFCDDJDDDMCJDHDFCHDHDGCDDJDDDLH",
-"EGAEDDABOAABOCEGHCHCPCHCBHJDJDEEJDEEJDEEJDAEJDEEAEJDEEJDEEJDEELH",
-"AHAAAAAAMCJDGCABHCHCBFOCPCJDEEJDEEJDEEAEEEEEAEJDEEFEFEFEEEEEJDGI",
-"AHAAAAPAAGGCABBBMCEGJDNCPCPCEEEEEEEEEEEEEEJDEEEEFEDIPIGFFEFEEENH",
-"EGOAKEAAABPAABKEHCHCHCHCMEBFABJDAEMCOCEEMCMCFEOCDDLEKHIDIDEEDDLH",
-"LHAEMCAAABABAEIFHCHCHCPCBHOCKEKEEEFEEEFEEEFEEEKEBFGEDIKFMEFEEEGI",
-"AHAAAAABGCJDABGCBBOCHGHCPCMDEEFEKEEEFEKEFEKEEEMEBFJFDIGEIFBFFEGI",
-"AHAAAAPAAHGCABBBMCJFMDOCPCJDMEKEKEMEKEKEKEKEMEIFGEFGEIIGJFGEMEGI",
-"AHAAAEAAABABGCNBDBOCNCNCMDEEMCEEEEMCJDKEDDDDLFCIDIEIPICIDIDIJDNH",
-"AHKEDDAAPAABOCKFPBICNCPCHGFEMEMEMEMEHFMEMEIFJFJELCCDCGBBCDLIIGHI",
-"EGAAAAABABJDMBNCPBADGENCMDMDMEHFIFHFMEHFIFMECHJEPCLDBGGDGDLIIGDJ",
-"AHAAAAAAAHEDKAOBEBBDCEODICMDIFIFMEIFIFIFIFIFCHEFLDPDOGGDPDMIFHHI",
-"AHAAOCABMBEABABAFABABAGBNELEHDKEHFDDEEIFJDEEFGCGLDPDPGPDPDAJMFHI",
-"AHDDEGABBBEABACAFABACBGBFHGEIFGGIFGGIFIFGGIFDHCGJEMHFIAFAFBJDHII",
-"AHAAAAABMBEAHAEAEADACABDODBEHGIFGGIFHGGGIFHGCHJHAFAFEFAFFFFJDHMJ",
-"AHAAAAAABEIADADAKACADAGBODNEGGHGIEIENFGGHGGGOHDGFFFFFFFFFFAJOHHI",
-"AHAAABABPCGAKADADAKADAFDODMFHIHIAIPFIIIIHIHIEJCIFFDGFFDGDGJJFJCK",
-"AHAAAHHCMBGAEAEAEAFAFAJCLGFKPEPEPEKDPEPEOIIKHKLIDGDGPGDGIHEKIKGK",
-"EGFCDDAANCJAIAIAIAIAIANDBKOJJBLALALBLAMANGFKHKFIMHPGMHFILIEKFKGK",
-"LHAAAABBNCFBJAJAJAEBGBDFBKOJBCNADCDCIBHBNGBKAKFIMHMHMHMHMHEKHKGK",
-"AHAAAAABADEBJCEBGBACACHEBKNIBCJBJBHBJBJBHHOJJJPIIHPGIHIHIHPJDKGK",
-"AHAAOCJDNCEBOBACOBOBOBHEEJNIKCLBKBBCKBCCKGHJJJMHDGIHPGDGIHEKEJCK",
-"AHAAKEABMBEBDBDBOBOBOBHENIAIKCDCDCDCDCECKGKIGJCIDGFFLGDGDGPJNJMJ",
-"CJAAOAABBBIADBHADBHAKAHEAIBIDCDCBCCCDCCCPFKIJIPGBGCFDGFFDGIJIIMJ",
-"AHAAAAABMBIABADBBAHAHAHEAIGHKCJBBCKBKBBCKGPHJIPGFFGFFFFFFFIJJILJ",
-"AHAAAAABMDFDFDBDFDNDBDHEFHJGDEDEDEDEOEDEOFPHMGBJBJAJBJBJBJMIOHDJ",
-"EGAAAAJDHGNFFHMGFHJGMGEHJGNFNFMGMGMGMGMGLGJGCHEHFHPHMGOHPHFHIGDJ",
-"LHAAOCIFIFIFLFLFMFMFJFLFIFJFHGIGMFIGNFMFMFLFIFLFHGIGFGIGIGHGJFCJ",
-"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;
-	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);
-	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);
-	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)
-{
-	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)
-{
-	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
-}
-
-bool
-BitMapQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
-{
-	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
-}
-
-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)
-{
-	if(!txt || !txt[0]) return false;
-	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
-}
-
-bool
-BitMapQT::oTextOutW(int x, int y, w_char *txt, int cb)
-{
-	if(!txt || !txt[0]) return false;
-	return com_TextOutW(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);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The menu class
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-RLPmenu::RLPmenu(QWidget *par, anyOutput *o, GraphObj *g)
-:QMenuBar(par, 0L)
-{
-	parent = par;		OutputClass = o;		BaseObj = g;
-	connect(this, SIGNAL(activated(int)), this, SLOT(doMenuItem(int)));
-}
-
-void
-RLPmenu::doMenuItem(int id)
-{
-	if(OutputClass) Undo.SetDisp(OutputClass);
-	if(parent && (parent->y() || parent->x())) {
-		CurrWidgetPos.x = parent->x();		CurrWidgetPos.y = parent->y();		CurrWidget = parent;
-		}
-	if(BaseObj) switch(id) {
-	case CM_REPANOV:
-		rep_anova(BaseObj, BaseObj->data);				return;
-	case CM_REPKRUSKAL:
-		rep_kruskal(BaseObj, BaseObj->data);			return;
-	case CM_CORRELM:
-		rep_correl(BaseObj, BaseObj->data, 0);			return;
-	case CM_CORRELT:
-		rep_correl(BaseObj, BaseObj->data, 1);			return;
-	}
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The display output class
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-OutputQT::OutputQT(GraphObj *g):BitMapQT(g, QAppl->desktop())
-{
-	int w, h;
-
-	HScroll = VScroll = 0L;
-	GetDesktopSize(&w, &h);
-	CreateNewWindow(BaseObj = g);
-	if(widget) {
-		widget->setBackgroundMode(QWidget::NoBackground);
-		if(CurrWidgetPos.x >= ((w>>1)-100))CurrWidgetPos.x = CurrWidgetPos.y = 50;
-		widget->show();
-		widget->move(CurrWidgetPos.x+=50, CurrWidgetPos.y+=50);
-		if(widget->x() || widget->y()) {
-			CurrWidgetPos.x = widget->x();	CurrWidgetPos.y = widget->y();
-			}
-		}
-}
-
-OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
-{
-	//assume fixed size (dialog) widget
-	if(widget = wi) {
-		wi->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
-		}
-	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 (rc->right > 40 && rc->bottom > 40);
-		}
-	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;
-
-	CurrWidget = widget;
-	switch(cid) {
-#ifdef Q_CHECK_PTR				//Qt version 3
-	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
-	case MC_TXTFRM:
-	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_COLWIDTH:
-	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_TXTFRM:
-	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_COLWIDTH:
-	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);
-		mask = new QBitmap(16, 16, drawpen_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 0, 0));
-		break;
-	case MC_DRAWREC:
-		bits = new QBitmap(16, 16, drect_bits, TRUE);
-		mask = new QBitmap(16, 16, drect_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 2, 2));
-		break;
-	case MC_DRAWRREC:
-		bits = new QBitmap(16, 16, drrect_bits, TRUE);
-		mask = new QBitmap(16, 16, drrect_mask, TRUE);
-		widget->setCursor(QCursor(*bits, *mask, 2, 2));
-		break;
-	case MC_DRAWELLY:
-		bits = new QBitmap(16, 16, delly_bits, TRUE);
-		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((CurrWidget = widget) && (widget->x() || widget->y())) {
-		CurrWidgetPos.x = widget->x();		CurrWidgetPos.y = widget->y();
-		}
-	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);
-	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);
-
-		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);
-		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
-		edit->insertSeparator();
-		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()));
-
-		QPopupMenu *anov = new QPopupMenu(widget);
-		anov->insertItem("&One Way Anova", CM_REPANOV);
-		anov->insertItem("&Kruskal Wallis", CM_REPKRUSKAL);
-
-		QPopupMenu *corr = new QPopupMenu(widget);
-		corr->insertItem("Correlation &Matrix", CM_CORRELM);
-		corr->insertItem("Tiled &Plots", CM_CORRELT);
-
-		QPopupMenu *stats = new QPopupMenu(widget);
-		stats->insertItem("&Sample Stats", widget, SLOT(cmSmplStat()));
-		stats->insertItem("&Comp. Means", widget, SLOT(cmRepCmeans()));
-		stats->insertItem("&Anova", anov);
-		stats->insertItem("&Regression", widget, SLOT(cmRepregr()));
-		stats->insertItem("C&orrelations", corr);
-		stats->insertItem("&2x2 Table", widget, SLOT(cmReptwoway()));
-
-		QPopupMenu *about = new QPopupMenu(widget);
-		about->insertItem("&About ...", widget, SLOT(cmAbout()));
-
-		menu = new RLPmenu(widget, this, BaseObj);
-		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);
-		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 RLPmenu(widget, this, BaseObj);
-		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()));
-		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 RLPmenu(widget, this, BaseObj);
-		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));
-		((RLPwidget*)widget)->mempic = mempic;
-		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);
-	setKeyCompression(true);
-}
-
-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()
-{
-	if(BaseObj) {
-		if(!BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)) return;
-		}
-	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::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);
-		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()
-{
-	BaseObj->Command(CMD_INSCOL, 0L, OutputClass);
-}
-
-void
-RLPwidget::cmDelRow()
-{
-	BaseObj->Command(CMD_DELROW, 0L, OutputClass);
-}
-
-void
-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
-RLPwidget::cmSmplStat()
-{
-	if(BaseObj) rep_samplestats(BaseObj, BaseObj->data);
-}
-
-void
-RLPwidget::cmRepCmeans()
-{
-	if(BaseObj) rep_compmeans(BaseObj, BaseObj->data);
-}
-
-void
-RLPwidget::cmRepregr()
-{
-	if(BaseObj) rep_regression(BaseObj, BaseObj->data);
-}
-
-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 *)
-{
-	CurrWidget = this;
-	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;
-			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();
-	CurrWidget = this;
-	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)
-{
-	int i;
-	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()};
-
-	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;
-	QChar qc;
-	w_char uc;
-
-	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:
-			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:
-			QString kres = e->text();
-			for(i = 0; i < kres.length(); i++) {
-				qc = kres.at(i);	uc = qc.unicode();
-				if(uc == 3) cmCopy();
-				else if(uc == 22) cmPaste();
-				else if(uc == 26) cmUndo();
-				else if(uc > 255) BaseObj->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass);
-				else BaseObj->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass);
-				}
-			break;
-		}
-	e->accept();
-}
-
-void
-RLPwidget::focusInEvent(QFocusEvent *e)
-{
-	if(x() || y()) {
-		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
-		}
-	CurrWidget = this;
-	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)
-{
-	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
-
-
-	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::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
-{
-	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
-}
-
-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;
-	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
-}
-
-bool
-PrintQT::oTextOutW(int x, int y, w_char *txt, int cb)
-{
-	if(!txt || !txt[0]) return false;
-	return com_TextOutW(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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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();				CurrWidget = this;
-	if(x() || y()) {
-		CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
-		}
-	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;
-
-	CurrWidget = this;
-	if(x() || y()) {
-		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
-		}
-	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)
-{
-	CurrWidget = this;
-	if(x() || y()) {
-		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);
-	o = new OutputQT(w);	o->units = defs.cUnits;
-	o->Erase(0x00e0e0e0L);	if(flags & 0x04) w->startTimer(100);
-	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);
-		}
-	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);
-		if(CurrWidgetPos.x > 50 && CurrWidgetPos.y > 50) {
-			CurrWidgetPos.x -= 50;		CurrWidgetPos.y -= 50;
-			}
-		}
-}
-
-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;
-}
-
+//QT_Spec.cpp, Copyright (c) 2001-2007 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 <qnamespace.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#if QT_VERSION < 0x040000
+	#include "QT3_Spec.h"
+#else
+	#include "QT_Spec.h"
+#endif
+
+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, *CurrWidget = 0L;
+POINT CurrWidgetPos = {0,0};
+static int mouse_buttons_down = 0;
+
+#if QT_VERSION >= 0x040000
+static QIcon *rlp_icon = 0L;
+#endif
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Export a QPixmap as supported by Qt
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int ExportQPixmap(GraphObj *g, char *filename, int type)
+{
+	double res, width, height;
+	int w, h;
+	anyOutput *bmo;
+	char *formats[] =  {0L, "Export Portable Network Grafics (*.png)", 
+		"Export Joint Photographic Experts Group (*.jpg)",
+		"Export X11 Pixmap (*.xpm)"}; 
+
+	if(!g || !filename) return 0;
+	res = 98.0;
+	width = g->GetSize(SIZE_GRECT_RIGHT) - g->GetSize(SIZE_GRECT_LEFT);
+	height = g->GetSize(SIZE_GRECT_BOTTOM) - g->GetSize(SIZE_GRECT_TOP);
+	if(GetBitmapRes(&res, &width, &height, formats[type])){
+		w = iround(width * res * Units[defs.cUnits].convert/25.4);
+		h = iround(height * res * Units[defs.cUnits].convert/25.4);
+		if(bmo = NewBitmapClass(w, h, res, res)){
+			bmo->VPorg.fy = -bmo->co2fiy(g->GetSize(SIZE_GRECT_TOP));
+			bmo->VPorg.fx = -bmo->co2fix(g->GetSize(SIZE_GRECT_LEFT));
+			bmo->Erase(0x00ffffffL);
+			g->DoPlot(bmo);
+			if(!((OutputQT*)bmo)->mempic->save(filename, 0, -1))
+				ErrorBox("An Error occured during export\n");
+			delete(bmo);
+			}
+		g->Command(CMD_REDRAW, 0L, 0L);
+		}
+
+	return 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)
+{
+#if QT_VERSION < 0x040000
+	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) {
+		if(!qf.selectedFile().isEmpty()) {
+			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;
+#else
+	QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0);
+	QStringList filters;
+	filters << "RLPlot workbook (*.rlw)" << "data files (*.csv)"
+		<< "tab separated (*.tsv)" << "XML (*.xml)";
+	int i, cb;
+	char *ext;
+	qf.setDirectory(defs.currPath);			qf.setViewMode(QFileDialog::Detail);
+	qf.selectFile(oldname);				qf.setFileMode(QFileDialog::AnyFile);
+	qf.setFilters(filters);
+	if(qf.exec() == QDialog::Accepted) {
+		if(!qf.selectedFiles().isEmpty()) {
+			cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data());
+			if(cb < 4 || UserFileName[cb-4] != '.'){
+				ext = (char*)qf.selectedFilter().toAscii().data();
+				for(i = 0; ext[i] && ext[i] != '*'; i++);
+				rlp_strcpy(UserFileName+cb, 5, ext+i+1);
+				}
+			defs.FileHistory(UserFileName);
+			return UserFileName;
+			}
+		}
+	return 0L;
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a new file name to store graph
+char *SaveGraphAsName(char *oldname)
+{
+#if QT_VERSION < 0x040000
+	QFileDialog qf(0,0,true);
+	QString filters("RLPlot files (*.rlp)");
+	int i, cb;
+	char *ext;
+
+	qf.setFilters(filters);				qf.setDir(defs.currPath);
+	qf.setSelection(oldname);			qf.setMode(QFileDialog::AnyFile);
+	if(qf.exec() == QDialog::Accepted) {
+		if(!qf.selectedFile().isEmpty()) {
+			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;
+#else
+	QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0);
+	QStringList filters;
+	filters << "RLPlot files (*.rlp)";
+	int i, cb;
+	char *ext;
+
+	qf.setDirectory(defs.currPath);			qf.setViewMode(QFileDialog::Detail);
+	qf.selectFile(oldname);				qf.setFileMode(QFileDialog::AnyFile);
+	qf.setFilters(filters);	
+	if(qf.exec() == QDialog::Accepted) {
+		if(!qf.selectedFiles().isEmpty()) {
+			cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data());
+			if(cb < 4 || UserFileName[cb-4] != '.'){
+				ext = (char*)qf.selectedFilter().toAscii().data();
+				for(i = 0; ext[i] && ext[i] != '*'; i++);
+				rlp_strcpy(UserFileName+cb, 5, ext+i+1);
+				}
+			defs.FileHistory(UserFileName);
+			return UserFileName;
+			}
+		}
+	return 0L;
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get file name to read graph
+char *OpenGraphName(char *oldname)
+{
+#if QT_VERSION < 0x040000
+	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+		"RLPlot files (*.rlp)", 0L);
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+#else
+	QString fileName = QFileDialog::getOpenFileName(0L, "Open Graph", oldname?oldname:defs.currPath,
+		"RLPlot files (*.rlp)");
+	if(!fileName.isEmpty()){
+		rlp_strcpy(UserFileName, 600, fileName.toAscii().data());
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to load data
+char *OpenDataName(char *oldname)
+{
+#if QT_VERSION < 0x040000
+	QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+		"RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n"
+		"RLPlot files (*.rlp)\nall files (*.*)", 0L);
+	if(!fileName.isEmpty()){
+		strcpy(UserFileName, fileName);
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+#else
+	QString fileName = QFileDialog::getOpenFileName(0L, "Open File", oldname?oldname:defs.currPath,
+		"RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n"
+		"RLPlot files (*.rlp)\nall files (*.*)");
+	if(!fileName.isEmpty()){
+		rlp_strcpy(UserFileName, 600, fileName.toAscii().data());
+		defs.FileHistory(UserFileName);
+		return UserFileName;
+		}
+	return 0L;
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to export graph
+void OpenExportName(GraphObj *g, char *oldname)
+{
+#if QT_VERSION < 0x040000
+	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"
+		"Tag Image File Format(*.tif *.tiff)", 0L);
+	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);
+		}
+#else
+	QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0);
+	QStringList filters;
+	filters << "Scalable Vector Graphics (*.svg)" << "Encapsulated Post Script (*.eps)" 
+	<< "Tag Image File Format (*.tif *.tiff)" << "Portable Network Graphics (*.png)"
+	<< "Joint Photographic Experts Group (*.jpg *.jpeg)" << "X11 Pixmap (*.xpm)";
+	int i, cb;
+	char *ext;
+	qf.setDirectory(defs.currPath);			qf.setViewMode(QFileDialog::Detail);
+	qf.selectFile(oldname);				qf.setFileMode(QFileDialog::AnyFile);
+	qf.setFilters(filters);
+	if(qf.exec() == QDialog::Accepted) {
+		if(!qf.selectedFiles().isEmpty()) {
+			cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data());
+			if(cb < 5 || (UserFileName[cb-4] != '.' && UserFileName[cb-5] != '.')){
+				ext = (char*)qf.selectedFilter().toAscii().data();
+				for(i = 0; ext[i] && ext[i] != '*'; i++);
+				rlp_strcpy(UserFileName+cb, 5, ext+i+1);
+				}
+			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 if(0==strcasecmp(".png", UserFileName+i-4)) {
+				ExportQPixmap(g, UserFileName, 1);
+				}
+			else if(0==strcasecmp(".jpg", UserFileName+i-4)) {
+				ExportQPixmap(g, UserFileName, 2);
+				}
+			else if(0==strcasecmp(".jpeg", UserFileName+i-5)) {
+				ExportQPixmap(g, UserFileName, 2);
+				}
+			else if(0==strcasecmp(".xpm", UserFileName+i-4)) {
+				ExportQPixmap(g, UserFileName, 3);
+				}
+			else ErrorBox("Unknown file extension or format");
+			}
+		g->Command(CMD_MOUSECURSOR, 0L, 0L);
+		}
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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)
+{
+	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, cb;
+
+	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;
+	case 1:		return 0;
+	default:	return 2;
+		}
+	return 0;
+}
+
+void Qt_Box()
+{
+	QMessageBox::aboutQt(QAppl->focusWidget(), "RLPlot uses Qt");
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Temporary visible objects: show action
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class eph_obj {
+public:
+	eph_obj(eph_obj *nxt);
+	virtual ~eph_obj();
+	virtual void DoPlot(QPainter *qp) {if(next) next->DoPlot(qp);};
+	virtual void Animate(anyOutput *o) {if(next) next->Animate(o);};
+
+	int cp, rx, ry, rw, rh, anim_base;
+	eph_obj *next;
+	POINT *points, p1, p2;
+	DWORD lcolor;
+	RECT bounds;
+	QPixmap *source;
+	bool invert;
+};
+
+class eph_line:public eph_obj {
+public:
+	eph_line(eph_obj *nxt, POINT * pts, int n, DWORD color);
+	~eph_line();
+	void DoPlot(QPainter *qp);
+};
+
+class eph_ellipse:public eph_obj {
+public:
+	eph_ellipse(eph_obj *nxt, POINT pt1, POINT pt2, DWORD color);
+	~eph_ellipse();
+	void DoPlot(QPainter *qp);
+};
+
+class eph_invert:public eph_obj {
+public:
+	eph_invert(eph_obj *nxt, QPixmap *src, int x, int y, int w, int h);
+	~eph_invert();
+	void DoPlot(QPainter *qp);
+};
+
+class eph_animated:public eph_obj {
+public:
+	eph_animated(eph_obj *nxt, int x, int y, int w, int h);
+	~eph_animated();
+	void DoPlot(QPainter *qp);
+	void Animate(anyOutput *o);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+eph_obj::eph_obj(eph_obj *nxt)
+{
+	next = nxt;	points = 0L;	lcolor = 0x0;
+}
+
+eph_obj::~eph_obj()
+{
+	if(next) delete(next);		next = 0L;
+	if(points) free(points);	points = 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+eph_line::eph_line(eph_obj *nxt, POINT * pts, int n, DWORD color):eph_obj(nxt)
+{
+	if(points = (POINT*)malloc(n * sizeof(POINT))) {
+		memcpy(points, pts, n * sizeof(POINT));
+		cp = n;			lcolor = color;
+		}
+}
+
+eph_line::~eph_line()
+{
+	if(next) delete(next);		next = 0L;
+	if(points) free(points);	points = 0L;
+}
+
+void
+eph_line::DoPlot(QPainter *qp)
+{
+	int i;
+	QPen qpen;
+
+	if(next)next->DoPlot(qp);
+	if(!points || cp < 2) return;
+	qpen.setColor(SwapRB(lcolor));		qpen.setWidth(1);
+	qpen.setStyle(Qt::SolidLine);		qpen.setCapStyle(Qt::RoundCap);
+	qpen.setJoinStyle(Qt::RoundJoin);	qp->setPen(qpen);
+	for (i = 1; i < cp; i++)qp->drawLine(points[i-1].x, points[i-1].y, points[i].x, points[i].y);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+eph_ellipse::eph_ellipse(eph_obj *nxt, POINT pt1, POINT pt2, DWORD color):eph_obj(nxt)
+{
+	p1.x = pt1.x;	p1.y = pt1.y;	p2.x = pt2.x;	p2.y = pt2.y;
+	lcolor = color;
+}
+
+eph_ellipse::~eph_ellipse()
+{
+	if(next) delete(next);		next = 0L;
+}
+
+void
+eph_ellipse::DoPlot(QPainter *qp)
+{
+	QPen qpen;
+
+	if(next)next->DoPlot(qp);
+	qpen.setColor(SwapRB(lcolor));		qpen.setWidth(1);
+	qpen.setStyle(Qt::SolidLine);		qpen.setCapStyle(Qt::RoundCap);
+	qpen.setJoinStyle(Qt::RoundJoin);	qp->setPen(qpen);
+	qp->drawArc(p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, 0, 5760);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+eph_invert::eph_invert(eph_obj *nxt, QPixmap *src, int x, int y, int w, int h):eph_obj(nxt)
+{
+	eph_obj *eo = nxt;
+
+	source = src;			invert = true;
+	rx = x;	ry = y;	rw = w;	rh = h;
+	while(eo) {
+		eo->invert = false;	eo = eo->next;
+		}
+}
+
+eph_invert::~eph_invert()
+{
+	if(next) delete(next);		next = 0L;
+}
+
+void
+eph_invert::DoPlot(QPainter *qp)
+{
+	if(next)next->DoPlot(qp);
+#if QT_VERSION >= 0x040000
+	QImage qi = (source->copy(rx, ry, rw, rh)).toImage();
+	if(invert) qi.invertPixels();
+	qp->drawImage(rx, ry, qi);
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+eph_animated::eph_animated(eph_obj *nxt, int x, int y, int w, int h):eph_obj(nxt)
+{
+	rx = x;	ry = y;	rw = w;	rh = h;
+	anim_base = 0;
+	SetMinMaxRect(&bounds, x, y, x+w, y+h);
+	IncrementMinMaxRect(&bounds, 2);
+
+}
+
+eph_animated::~eph_animated()
+{
+	if(next) delete(next);		next = 0L;
+}
+
+void
+eph_animated::DoPlot(QPainter *qp)
+{
+	int i, j, sx, sy, rlp;
+	QPen qpen;
+	POINT pts[3];
+
+	if(next)next->DoPlot(qp);
+	if(!rw || !rh) return;
+
+	rlp = anim_base;				qpen.setWidth(1);
+	qpen.setStyle(Qt::SolidLine);			qpen.setCapStyle(Qt::RoundCap);
+	qpen.setJoinStyle(Qt::RoundJoin);
+	for(i = 0; i < 4; i++) {
+		qpen.setColor((DWORD)0x00ffffffL);	qp->setPen(qpen);
+		switch(i) {
+		case 0:
+			pts[0].x = rx;			pts[0].y = ry;
+			pts[2].x = rx+rw;		pts[2].y = ry;
+			sx = rw > 0 ? 1 : -1;		sy = 0;
+			break;
+		case 1:
+			pts[0].x = rx+rw;		pts[0].y = ry;
+			pts[2].x = rx+rw;		pts[2].y = ry+rh;
+			sx = 0;				sy = rh > 0 ? 1 : -1;
+			break;
+		case 2:
+			pts[0].x = rx+rw;		pts[0].y = ry+rh;
+			pts[2].x = rx;			pts[2].y = ry+rh;
+			sx = rw > 0 ? -1 : 1;		sy = 0;
+			break;
+		case 3:
+			pts[0].x = rx;			pts[0].y = ry+rh;
+			pts[2].x = rx;			pts[2].y = ry;
+			sx = 0;				sy = rh > 0 ? -1: 1;
+			break;
+			}
+		qp->drawLine(pts[0].x, pts[0].y, pts[2].x, pts[2].y);
+		qpen.setColor((DWORD)0x0L);		qp->setPen(qpen);
+		pts[1].x = pts[0].x;			pts[1].y = pts[0].y;
+		for( ; pts[1].x != pts[2].x || pts[1].y != pts[2].y; ) {
+			pts[1].x += sx;			pts[1].y += sy;
+			rlp = (rlp+1) & 0x07;
+			if(rlp == 0) {
+				pts[0].x = pts[1].x;	pts[0].y = pts[1].y;
+				}
+			else if(rlp == 3) {
+				qp->drawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+				}
+			}
+		if(rlp < 3 && (pts[0].x != pts[1].x || pts[0].y != pts[1].y)) 
+			qp->drawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+		}
+}
+
+#if QT_VERSION < 0x040000
+void
+eph_animated::Animate(anyOutput *o)
+{
+	if(next) next->Animate(o);
+	anim_base = (anim_base-1) & 0x07;
+	if(((OutputQT*)o)->widget) {
+		QPainter qp(((OutputQT*)o)->widget);	DoPlot(&qp);
+		}
+	else if(((OutputQT*)o)->dlgwidget) {
+		QPainter qp(((OutputQT*)o)->dlgwidget);	DoPlot(&qp);
+		}
+}
+#else
+void
+eph_animated::Animate(anyOutput *o)
+{
+	if(next) next->Animate(o);
+	anim_base = (anim_base-1) & 0x07;
+	o->UpdateRect(&bounds, false);
+}
+#endif
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Display blinking text cursor
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static anyOutput *oTxtCur = 0L, *txtcur0 = 0L, *txtcur1 = 0L;
+static anyOutput *oCopyMark = 0L;
+RECT rTxtCur, rCopyMark;
+static bool bTxtCur = false,  bSuspend = false;
+static DWORD coTxtCur = 0x0L;
+static TxtCurBlink *cTxtCur = 0L;
+static POINT ptTxtCurLine[2];
+
+void HideTextCursor()
+{
+	if(txtcur0 && txtcur1) {
+		DelBitmapClass(txtcur1);
+		RestoreRectBitmap(&txtcur0, &rTxtCur, oTxtCur);
+		}
+	else if(oTxtCur) {
+		bTxtCur = false;
+		oTxtCur->UpdateRect(&rTxtCur, false);
+		}
+	txtcur0 = txtcur1 = oTxtCur = 0L;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+	if(oTxtCur && oTxtCur == out) HideTextCursor();
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+	LineDEF liTxtCur = {0.0, 1.0, 0x0L, 0L};
+
+	coTxtCur = color;				HideTextCursor();
+	oTxtCur = out;					bSuspend = false;
+	memcpy(&rTxtCur, disp, sizeof(RECT));		ptTxtCurLine[0].x = 0;
+	ptTxtCurLine[1].x = rTxtCur.right - rTxtCur.left;
+	ptTxtCurLine[1].y = rTxtCur.bottom-rTxtCur.top;
+	rTxtCur.bottom++;				rTxtCur.right++;
+	bTxtCur = true;
+	txtcur0 = GetRectBitmap(&rTxtCur, out);		txtcur1 = GetRectBitmap(&rTxtCur, out);
+	liTxtCur.color = color;				txtcur1->SetLine(&liTxtCur);
+	txtcur1->oPolyline(ptTxtCurLine, 2);		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(oCopyMark) {
+		if(((OutputQT*)oCopyMark)->ShowObj) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowObj);
+		if(((OutputQT*)oCopyMark)->ShowAnimated) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated);
+		(((OutputQT*)oCopyMark)->ShowObj) = (((OutputQT*)oCopyMark)->ShowAnimated) = 0L;
+		oCopyMark->UpdateRect(&rCopyMark, false);
+		}
+	oCopyMark = 0L;
+}
+
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
+{
+	int i;
+
+	HideCopyMark();			bSuspend = false;
+	if(!out || !mrk || !nRec || !cTxtCur) return;
+	if(((OutputQT*)out)->ShowAnimated) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated);
+	((OutputQT*)out)->ShowAnimated = (new eph_animated((eph_obj*) 0L, mrk[0].left, mrk[0].top, 
+		mrk[0].right - mrk[0].left, mrk[0].bottom - mrk[0].top));
+	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);
+		}
+	IncrementMinMaxRect(&rCopyMark, 2);
+	out->UpdateRect(&rCopyMark, false);
+}
+
+void InvalidateOutput(anyOutput *o)
+{
+	if(!o || !cTxtCur) return;
+	if(o == oCopyMark) oCopyMark = 0L;
+	if(o == oTxtCur) {
+		oTxtCur = 0L;	bTxtCur = false;
+		}
+}
+
+void SuspendAnimation(anyOutput *o, bool bSusp)
+{
+	if(!o || !cTxtCur) return;
+	if(!bSusp) bSuspend = false;
+	else {
+		if(o == oCopyMark) bSuspend = bSusp;
+		if(o == oTxtCur) bSuspend = bSusp;
+		}
+}
+
+static void showCopyMark()
+{
+	if(oCopyMark && ((OutputQT*)oCopyMark)->ShowAnimated) 
+		((eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated))->Animate(oCopyMark);
+
+}
+
+TxtCurBlink::TxtCurBlink():QObject(CurrWidget)
+{
+	isVis = false;		count = 0;
+	startTimer(60);
+}
+
+void
+TxtCurBlink::Show()
+{
+	count = -4;			isVis = true;
+	if(bTxtCur && oTxtCur && txtcur0 && txtcur1){
+		oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur1, 0, 0, rTxtCur.right - rTxtCur.left, 
+			rTxtCur.bottom - rTxtCur.top, false);
+		oTxtCur->UpdateRect(&rTxtCur, false);
+		}
+}
+
+void
+TxtCurBlink::timerEvent(QTimerEvent *ev)
+{
+	if(bSuspend) return;		showCopyMark();
+	if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
+		ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return;
+	count++;
+	if(count < 10) return;
+	count = 0;
+	if(bTxtCur && oTxtCur) {
+		if(isVis) {
+			oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur0, 0, 0, rTxtCur.right - rTxtCur.left, 
+				rTxtCur.bottom - rTxtCur.top, false);
+			oTxtCur->UpdateRect(&rTxtCur, false);
+			isVis = false;
+			}
+		else {
+			oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur1, 0, 0, rTxtCur.right - rTxtCur.left, 
+				rTxtCur.bottom - rTxtCur.top, false);
+			oTxtCur->UpdateRect(&rTxtCur, false);
+			isVis = true;
+			}
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Clipboard support: the clipboard server uses sockets
+// code based on Qt example code
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static RLPserver *rlpsrv = 0L;
+
+#ifdef RLP_PORT
+static char *cb_owner = 0L;		//user name
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// close remote clipboard server
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool CloseCB(char *msg)
+{
+	int i, cb, sock;
+	char buff[1024];
+	sockaddr_in cb_host;
+	hostent *hp;
+
+	if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return false;
+	if(!(hp = gethostbyname("127.0.0.1")))return false;
+	memset(&cb_host, 0, sizeof(cb_host));
+	memcpy(&cb_host.sin_addr, hp->h_addr, hp->h_length);
+	cb_host.sin_family = AF_INET;		cb_host.sin_port = htons(RLP_PORT);
+	if(connect(sock, (sockaddr*)&cb_host, sizeof(cb_host)) >= 0) {
+//		if(ioctl(sock, FIONREAD, &i) >= 0) {
+//			if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+//				if(strcmp("user:", buff) == 0) {
+//					write(sock, cb_owner, strlen(cb_owner)+1);
+//					ioctl(sock, BLKFLSBUF, &i);
+//					}
+//				}
+//			}
+		write(sock, msg, strlen(msg)+1);
+		close(sock);		return true;
+		}
+	close(sock);	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// connect and read remote clipboard server
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool ReadCB(char *server, GraphObj *g)
+{
+	int i, j, sock, cb;
+	char buff[1024], line[25], format[20], *cb_data;
+	sockaddr_in cb_host;
+	hostent *hp;
+	bool bRet = false;
+
+	if(!g || ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)) return false;
+	if(!(hp = gethostbyname("127.0.0.1")))return false;
+	memset(&cb_host, 0, sizeof(cb_host));
+	memcpy(&cb_host.sin_addr, hp->h_addr, hp->h_length);
+	cb_host.sin_family = AF_INET;		cb_host.sin_port = htons(RLP_PORT);
+	if(connect(sock, (sockaddr*)&cb_host, sizeof(cb_host)) >= 0) { 
+//		if(ioctl(sock, FIONREAD, &i) >= 0) {
+//			if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+//				if(strcmp("user:", buff) == 0) {
+//					write(sock, cb_owner, strlen(cb_owner)+1);
+//					ioctl(sock, BLKFLSBUF, &i);
+//					}
+//				}
+//			}
+		if(!(write(sock, "enum formats\n", 14) > 0)) {
+			close(sock);	return false;
+			}
+		if((cb = read(sock, &buff, 1024)) && cb < 1024) {
+			for(i = 0, format[0] = 0; i < cb; ) {
+				for (j = 0; j < 20 && i < cb; j++) {
+					if((line[j] = buff[i++]) < 32) break;
+					}
+				line[j] = 0;
+				if(g->Id == GO_SPREADDATA && (strcmp(line, "text/xml") == 0 
+					|| strcmp(line, "text/rlp-graph") == 0 || strcmp(line, "text/rlp-page") == 0)) {
+					rlp_strcpy(format, 20, line);	i = cb;
+					}
+				else if((g->Id == GO_PAGE || g->Id == GO_GRAPH) 
+					&& (strcmp(line, "text/rlp-graph") == 0 || strcmp(line, "text/rlp-page") == 0)) {
+					rlp_strcpy(format, 20, line);	i = cb;
+					}
+				}
+			if(format[0] && (cb_data = (char*)malloc(j = 1024))) {
+				cb = rlp_strcpy(line, 25, "get ");	cb += rlp_strcpy(line+cb, 25-cb, format);
+				line[cb++] = '\n';			line[cb++] = 0;
+				if(write(sock, line, cb) >= 0) {
+					cb = 0;
+					while((i = read(sock, cb_data+cb, 1024)) == 1024) {
+						cb_data = (char*)realloc(cb_data, (j += 1024));
+						cb += i;
+						}
+					cb += i;	cb_data[cb] = 0;
+					if(cb > 5 && g->Id == GO_SPREADDATA) {
+						bRet = true;
+						if(strcmp(format, "text/xml") == 0) 
+							g->Command(CMD_PASTE_XML, (void*)cb_data, 0L);
+						else if(strcmp(format, "text/rlp-graph") == 0) 
+							OpenGraph(g, 0L, (unsigned char*)cb_data, true);
+						else if(strcmp(format, "text/rlp-page") == 0) 
+							OpenGraph(g, 0L, (unsigned char*)cb_data, true);
+						else bRet = false;
+						}
+					else if(cb > 5 && (g->Id == GO_PAGE || g->Id == GO_GRAPH)) {
+						bRet = true;
+						if(strcmp(format, "text/rlp-graph") == 0)
+							OpenGraph(g, 0L, (unsigned char*)cb_data, true);
+						else if(strcmp(format, "text/rlp-page") == 0)
+							OpenGraph(g, 0L, (unsigned char*)cb_data, true);
+						else bRet = false;
+						}
+					}
+				}
+			}
+		}
+	close(sock);	return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// this thread is a single-threaded server
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void *ServerCB(void* attr)
+{
+	int cb, msgsock;
+	char buff[1024], *data;
+	static char *fmts_1 = "text/xml\ntext/plain\n";
+	static char *fmts_2 = "text/rlp-graph\n";
+	static char *fmts_3 = "text/rlp-page\n";
+	RLPserver *parent = (RLPserver*)attr;
+	sockaddr_in client;
+	socklen_t clientlen = sizeof(client);
+	bool bValid;
+
+	if(!parent) return 0L;
+	for( ; ; ) {
+		bValid = false;
+		if((msgsock = accept(parent->Socket(), (sockaddr*)&client, &clientlen)) >= 0){
+//			if(write(msgsock, "user:", 6) > 0) {
+//				if((cb = read(msgsock, &buff, 1024) > 0) && cb < 1024){
+//					if(strcmp(buff, cb_owner) == 0) bValid = true;
+//					}
+//				}
+
+			bValid = true;			//FIXME
+
+			while(bValid && (cb = read(msgsock, &buff, 1024) > 0) && cb < 1024) {
+				if(strcmp(buff, "enum formats\n") == 0 && parent->SourceGO) {
+					if(parent->SourceGO->Id == GO_SPREADDATA) {
+						write(msgsock, fmts_1, strlen(fmts_1)+1);
+						}
+					else if(parent->SourceGO->Id == GO_GRAPH) {
+						write(msgsock, fmts_2, strlen(fmts_2)+1);
+						}
+					else if(parent->SourceGO->Id == GO_PAGE) {
+						write(msgsock, fmts_3, strlen(fmts_3)+1);
+						}
+					else close(msgsock);
+					}
+				else if(strcmp(buff, "get text/xml\n") == 0) {
+					if(data = parent->GetXML()) write(msgsock, data, strlen(data)+1);
+					close(msgsock);
+					}
+				else if(strcmp(buff, "get text/plain\n") == 0) {
+					if(data = parent->GetTXT()) write(msgsock, data, strlen(data)+1);
+					close(msgsock);
+					}
+				else if(strcmp(buff, "get text/rlp-graph\n") == 0 
+					|| strcmp(buff, "get text/rlp-page\n") == 0) {
+					if(data = parent->GetRLP()) write(msgsock, data, strlen(data)+1);
+					close(msgsock);
+					}
+				else if(strcmp(buff, "exit\n") == 0 || strcmp(buff, "close\n") == 0
+					|| strcmp(buff, "exit") == 0 || strcmp(buff, "close") == 0) {
+					delete(parent);		return 0L;
+					}
+				else if(strcmp(buff, "exit_thread\n") == 0) {
+					return 0L;
+					}
+				else if(strcmp(buff, "user\n") == 0 || strcmp(buff, "user:") == 0) {
+					write(msgsock, cb_owner, strlen(cb_owner)+1);
+					}
+				}
+			close(msgsock);
+			}
+		else if(msgsock < 0) return 0L;
+		}
+	return 0L;
+}
+// end of thread
+#endif	//RLP_PORT
+
+RLPserver::RLPserver(QObject* parent, GraphObj *g)
+{
+	text_xml = text_rlp = text_plain = 0L;
+	SetGO(g);
+#ifdef RLP_PORT
+	int i;
+	sockaddr_in server, client;
+	socklen_t clientlen = sizeof(client);
+
+	if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) return;
+	i = 1;
+	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
+	if(fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK) < 0);
+	memset(&server, 0, sizeof(server));
+	server.sin_family = AF_UNIX;
+	server.sin_addr.s_addr = INADDR_ANY;
+	server.sin_port = htons(RLP_PORT);
+	if(bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) return;
+	if(listen(sock, 5) < 0) return;
+	pthread_attr_init(&thread_attr);
+	pthread_create(&thread, &thread_attr, ServerCB, this);
+#endif
+}
+
+RLPserver::~RLPserver()
+{
+	rlpsrv = 0L;
+	HideCopyMark();
+	if(text_xml) free(text_xml);		text_xml =  0L;
+	if(text_rlp) free(text_rlp);		text_rlp =  0L;
+	if(text_plain) free(text_plain);	text_plain = 0L;
+	if(SourceGO) SourceGO->Command(CMD_HIDEMARK, 0L, 0L);
+#ifdef RLP_PORT
+	CloseCB("exit_thread\n");		close(sock);
+	pthread_attr_destroy(&thread_attr);
+
+#endif
+}
+
+void 
+RLPserver::SetGO(GraphObj *g)
+{
+	QClipboard *cb;
+
+	SourceGO = g;
+	if(text_xml) free(text_xml);		text_xml =  0L;
+	if(text_rlp) free(text_rlp);		text_rlp =  0L;
+	if(text_plain) free(text_plain);	text_plain = 0L;
+	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+		SourceGO->Command(CMD_COPY_TSV, &text_plain, 0L);
+		if(text_plain && text_plain[0]){
+			cb = QAppl->clipboard();
+			cb->clear();
+#if QT_VERSION < 0x030000				//n.a. in Qt version 2
+			cb->setText(text_plain, QClipboard::Clipboard);
+			cb->setText(text_plain, QClipboard::Selection);
+#else
+			cb->setText(text_plain);
+#endif
+			}
+		}
+}
+
+char *
+RLPserver::GetXML()
+{
+	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+		if(!text_xml) SourceGO->Command(CMD_COPY_XML, &text_xml, 0L);
+		return text_xml;
+		}
+	return 0L;
+}
+
+char *
+RLPserver::GetRLP()
+{
+	long cb;
+
+	if(SourceGO) {
+		text_rlp = GraphToMem(SourceGO, &cb);
+		return text_rlp;
+		}
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process paste command: check for clipboard contents
+void TestClipboard(GraphObj *g)
+{
+	QClipboard *cb;
+
+	if(!g) return;
+	if(rlpsrv && rlpsrv->SourceGO) {
+		if(rlpsrv->SourceGO->Id == GO_GRAPH || rlpsrv->SourceGO->Id == GO_PAGE
+			|| rlpsrv->SourceGO->Id == GO_POLYLINE || rlpsrv->SourceGO->Id == GO_POLYGON
+			|| rlpsrv->SourceGO->Id == GO_RECTANGLE || rlpsrv->SourceGO->Id == GO_ROUNDREC
+			|| rlpsrv->SourceGO->Id == GO_ELLIPSE || rlpsrv->SourceGO->Id == GO_BEZIER
+			)
+			OpenGraph(g, 0L, (unsigned char*)rlpsrv->GetRLP(), true);
+		else if(rlpsrv->SourceGO->Id == GO_SPREADDATA && g->Id == GO_SPREADDATA)
+			g->Command(CMD_PASTE_XML, (void*)rlpsrv->GetXML(), 0L);
+		}
+#ifdef RLP_PORT
+	else if(ReadCB(0L, g)) return;
+#endif
+#if QT_VERSION < 0x040000
+	QDragObject *mime;
+
+	if((cb = QAppl->clipboard()) && (mime = (QDragObject *)cb->data())) {
+		if(g->Id == GO_SPREADDATA) {
+			if(mime->provides("text/plain")) {
+				ProcMemData(g, (unsigned char*)cb->text().latin1(), true);
+				return;
+				}
+			}
+		}
+#else
+	const QMimeData *mime;
+	const char *cdata;
+
+	if((cb = QAppl->clipboard()) && (mime = cb->mimeData())) {
+		if(g->Id == GO_SPREADDATA) {
+			if(mime->hasFormat("text/plain")) {
+				QByteArray b = mime->data("text/plain");
+				if(cdata = b) ProcMemData(g, (unsigned char*)cdata, true);
+				return;
+				}
+			}
+		}
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Copy spreadsheet or graph to clipboard
+void CopyData(GraphObj *g)
+{
+	QAppl->clipboard()->clear();
+	if(rlpsrv) {
+		if(rlpsrv->ok()) rlpsrv->SetGO(g);
+		else {
+			delete rlpsrv;
+			rlpsrv = new RLPserver(0, g);
+			}
+		}
+	else rlpsrv = new RLPserver(0, g);
+}
+
+void CopyGraph(GraphObj *g)
+{
+	if(g->Id == GO_PAGE && CurrGraph) CopyData(CurrGraph);
+	else CopyData(g);
+}
+
+void EmptyClip()
+{
+	if(rlpsrv) {
+		delete(rlpsrv);			rlpsrv = 0;
+		}
+	else CloseCB("close\n");
+	HideCopyMark();
+	QAppl->clipboard()->clear();
+}
+
+void CopyText(char *txt, int len)
+{
+	QClipboard *cb;
+
+	HideCopyMark();
+	if(!(cb = QAppl->clipboard()) || !txt || !txt[0]) return;
+	cb->clear();
+	cb->setText(txt);
+}
+
+unsigned char* PasteText()
+{
+	QClipboard *cb = QAppl->clipboard();
+#if QT_VERSION < 0x040000
+	return (unsigned char*)cb->text().ascii();
+#else
+	return (unsigned char*)cb->text().toAscii().data();
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get display (desktop) size
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void GetDesktopSize(int *width, int *height)
+{
+#if QT_VERSION < 0x040000
+	QWidget *d = QApplication::desktop();
+#else
+	QDesktopWidget *d = QApplication::desktop();
+#endif
+	if(d) {
+		*width = d->width();	*height = d->height();
+		}
+	if(!d || *width < 800 || *height < 600){
+		*width = 1280;		*height = 1024;
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code for all QT output classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool com_QStringExt(QString txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	QRect rc;
+
+	if(cb >0)txt.truncate(cb);
+	rc = qP->boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, txt);
+#if QT_VERSION < 0x040000
+	*width = rc.rRight() - rc.rLeft();	*height = TxtSet->iSize +2;
+#else
+	*width = rc.width();			*height = TxtSet->iSize +2;
+#endif
+	return true;
+}
+
+bool
+com_GetTextExtent(char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
+	else return com_QStringExt(QString(txt), width, height, cb > 0 ? cb : (int)strlen(txt), TxtSet, qP);
+}
+
+bool
+com_GetTextExtentW(w_char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	int i;
+	QString wtxt(0);
+
+	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
+	for(i = 0; txt[i] && i < cb; i++) wtxt.append(QChar(txt[i]));
+	com_QStringExt(wtxt, width, height, cb, TxtSet, qP);
+}
+
+bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+	int i, w, h, ix, iy;
+	QBrush oldBrush;
+	QPen oldPen, currPen;
+#if QT_VERSION >= 0x040000
+	QMatrix xf, dxf;
+#else
+	QWMatrix xf, dxf;
+#endif
+
+	if(!TxtSet->iSize && TxtSet->fSize > 0.0) TxtSet->iSize = o->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);
+	oldBrush = qP->brush();						dxf = qP->worldMatrix();
+	oldPen = currPen = qP->pen();				iy = y;
+	com_QStringExt(txt, &w, &h, -1, TxtSet, qP);
+	if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1);
+	else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
+	else ix = x;
+	currPen.setColor(SwapRB(TxtSet->ColTxt));
+	qP->setPen(currPen);
+	if(fabs(TxtSet->RotBL) >.01 || fabs(TxtSet->RotCHAR) >.01) {
+		xf.translate(x, y);
+		xf.rotate(-TxtSet->RotBL);
+		qP->setWorldMatrix(xf, TRUE);
+		if(TxtSet->Mode == TXM_OPAQUE){
+			currPen.setColor(SwapRB(TxtSet->ColBg));
+			qP->setPen(currPen);
+			qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+			qP->drawRect(0, - iround(h*.8), w, h);
+			currPen.setColor(SwapRB(TxtSet->ColTxt));
+			qP->setPen(currPen);
+			}
+		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);
+		}
+	else {
+		if(TxtSet->Mode == TXM_OPAQUE){
+			currPen.setColor(SwapRB(TxtSet->ColBg));
+			qP->setPen(currPen);
+			qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+			qP->drawRect(ix, iy - iround(h*.8), w, h);
+			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);
+		qP->drawText(ix, iy, txt);
+		}
+	oldPen.setCapStyle(Qt::RoundCap);
+	oldPen.setJoinStyle(Qt::RoundJoin);
+	qP->setPen(oldPen);
+	qP->setBrush(oldBrush);
+	qP->setWorldMatrix(dxf, FALSE);
+	return true;
+}
+
+bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+	int i, w, h, ix, iy;
+	QString txt(ctxt);
+
+	if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false;
+	if(TxtSet->Font==FONT_GREEK) {
+		txt.truncate(0);
+		for(i = 0; ctxt[i]; i++) {
+			if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391));
+			else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1));
+			else txt.append(QChar(ctxt[i]));
+			}
+		}
+	return com_QStringOut(x, y, txt, TxtSet, qP, o);
+}
+
+bool com_TextOutW(int x, int y, w_char *wtxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+	int i;
+	QString txt(0);
+
+	if(!wtxt || !wtxt[0] || !TxtSet || !qP || !o) return false;
+	for(i = 0; wtxt[i]; i++) txt.append(QChar(wtxt[i]));
+	return com_QStringOut(x, y, txt, TxtSet, qP, o);
+}
+
+bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP)
+{
+	bool RetVal;
+
+	if(!set->iSize && set->fSize > 0.0) set->iSize = o->un2iy(set->fSize);
+	if(!set->iSize) return false;
+	RetVal = o->anyOutput::SetTextSpec(set);
+	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((TxtSet->iSize > 1) ? (int)(TxtSet->iSize*0.71) : 1);
+		else qF.setPointSize((TxtSet->iSize > 2) ? TxtSet->iSize : 2);
+		switch(TxtSet->Font){
+		case FONT_HELVETICA:
+		default:			qF.setFamily("Helvetica");			break;
+		case FONT_GREEK:
+		case FONT_TIMES:	qF.setFamily("Times");				break;
+		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
+const 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
+const 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
+const static char *RLPlot_xpm[]={
+/* width height ncolors chars_per_pixel */
+"32 32 169 2",
+/* colors */
+"AA c #FFFFFFFFFFFF",	"BA c #FFFFF7F79494",	"CA c #FFFFF7F78484",
+"DA c #FFFFF7F77373",	"EA c #FFFFF7F75252",	"FA c #FFFFF7F74242",
+"GA c #FFFFF7F73939",	"HA c #FFFFEFEF8C8C",	"IA c #FFFFEFEF4A4A",
+"JA c #FFFFEFEF2929",	"KA c #F7F7E7E77B7B",	"LA c #F7F7C6C6ADAD",
+"MA c #F7F7B5B59C9C",	"NA c #F7F7ADAD9494",	"OA c #EFEFF7F7F7F7",
+"PA c #EFEFF7F7EFEF",	"AB c #EFEFEFEFEFEF",	"BB c #EFEFEFEFDEDE",
+"CB c #EFEFE7E7A5A5",	"DB c #EFEFDEDE7373",	"EB c #EFEFDEDE3939",
+"FB c #EFEFDEDE2929",	"GB c #EFEFD6D64242",	"HB c #EFEFA5A58C8C",
+"IB c #EFEF94947B7B",	"JB c #EFEF84847373",	"KB c #EFEF84846363",
+"LB c #EFEF7B7B7373",	"MB c #E7E7E7E7CECE",	"NB c #E7E7E7E79494",
+"OB c #E7E7DEDE6B6B",	"PB c #E7E7DEDE5252",	"AC c #E7E7CECE5252",
+"BC c #E7E77B7B6363",	"CC c #E7E773735A5A",	"DC c #E7E76B6B5252",
+"EC c #E7E75A5A4A4A",	"FC c #DEDEE7E7F7F7",	"GC c #DEDEE7E7EFEF",
+"HC c #DEDEDEDEDEDE",	"IC c #DEDEDEDEBDBD",	"JC c #DEDECECE4A4A",
+"KC c #DEDE4A4A3939",	"LC c #D6D6EFEFCECE",	"MC c #D6D6DEDEEFEF",
+"NC c #D6D6DEDECECE",	"OC c #CECEDEDEDEDE",	"PC c #CECED6D6CECE",
+"AD c #CECECECEB5B5",	"BD c #CECECECE5A5A",	"CD c #C6C6E7E7C6C6",
+"DD c #C6C6DEDEEFEF",	"ED c #C6C6D6D67373",	"FD c #C6C6CECE4A4A",
+"GD c #BDBDDEDEB5B5",	"HD c #BDBDCECEE7E7",	"ID c #BDBDCECECECE",
+"JD c #BDBDC6C6D6D6",	"KD c #BDBD39394242",	"LD c #B5B5DEDEADAD",
+"MD c #B5B5BDBDCECE",	"ND c #B5B5BDBD4242",	"OD c #B5B5B5B59C9C",
+"PD c #ADADD6D6ADAD",	"AE c #ADADCECEDEDE",	"BE c #ADADBDBDB5B5",
+"CE c #ADADB5B54242",	"DE c #ADAD4A4A5252",	"EE c #A5A5BDBDDEDE",
+"FE c #A5A5BDBDCECE",	"GE c #A5A5ADADB5B5",	"HE c #A5A5ADAD4242",
+"IE c #A5A563637B7B",	"JE c #9C9CD6D6A5A5",	"KE c #9C9CBDBDD6D6",
+"LE c #9C9CBDBDBDBD",	"ME c #9C9CADADCECE",	"NE c #9C9CADADA5A5",
+"OE c #9C9C52525252",	"PE c #9C9C4A4A5252",	"AF c #9494CECE9C9C",
+"BF c #9494B5B5CECE",	"CF c #9494ADAD5A5A",	"DF c #9494ADAD3939",
+"EF c #8C8CCECE9494",	"FF c #8C8CCECE8C8C",	"GF c #8C8CB5B5B5B5",
+"HF c #8C8CADADD6D6",	"IF c #8C8CADADCECE",	"JF c #8C8CADADB5B5",
+"KF c #8C8CADADA5A5",	"LF c #8C8C9C9CB5B5",	"MF c #8C8C9C9CADAD",
+"NF c #8C8C8C8CA5A5",	"OF c #8C8C52526363",	"PF c #8C8C42425252",
+"AG c #8484B5B5CECE",	"BG c #7B7BCECE9494",	"CG c #7B7BC6C68484",
+"DG c #7B7BC6C67B7B",	"EG c #7B7BADADC6C6",	"FG c #7B7BADADADAD",
+"GG c #7B7B9C9CC6C6",	"HG c #7B7B9C9CB5B5",	"IG c #7B7B9C9CADAD",
+"JG c #7B7B84849C9C",	"KG c #7B7B42425252",	"LG c #737384848C8C",
+"MG c #737373738484",	"NG c #737339395252",	"OG c #6B6BC6C68484",
+"PG c #6B6BBDBD7B7B",	"AH c #6B6BA5A5CECE",	"BH c #6B6B9C9CBDBD",
+"CH c #6B6B9C9CA5A5",	"DH c #6B6B94949C9C",	"EH c #6B6B8C8CA5A5",
+"FH c #6B6B8C8C9C9C",	"GH c #6B6B6B6B7B7B",	"HH c #6B6B42425252",
+"IH c #6363BDBD6B6B",	"JH c #6363B5B58C8C",	"KH c #6363A5A58C8C",
+"LH c #63639C9CC6C6",	"MH c #5A5AB5B56363",	"NH c #5A5A9C9CBDBD",
+"OH c #5A5A8C8C9C9C",	"PH c #5A5A7B7B8C8C",	"AI c #5A5A6B6B8484",
+"BI c #5A5A63637B7B",	"CI c #5252BDBD7373",	"DI c #5252ADAD8484",
+"EI c #5252A5A57B7B",	"FI c #4A4AB5B55A5A",	"GI c #4A4A8C8CBDBD",
+"HI c #4A4A8C8CADAD",	"II c #4A4A7B7B9C9C",	"JI c #4A4A7B7B8484",
+"KI c #4A4A6B6B7B7B",	"LI c #42429C9C7373",	"MI c #42428C8C7B7B",
+"NI c #42425A5A7373",	"OI c #42424A4A6B6B",	"PI c #3939ADAD6B6B",
+"AJ c #3939ADAD5A5A",	"BJ c #39399C9C6B6B",	"CJ c #39398484BDBD",
+"DJ c #39397B7BADAD",	"EJ c #39397B7B8C8C",	"FJ c #393973737B7B",
+"GJ c #313163637B7B",	"HJ c #31315A5A7B7B",	"IJ c #292984846B6B",
+"JJ c #29296B6B7B7B",	"KJ c #21217B7BB5B5",	"LJ c #21217373A5A5",
+"MJ c #212173739C9C",	"NJ c #21216B6B8C8C",	"OJ c #212152527373",
+"PJ c #181884846363",	"AK c #18186B6B7B7B",	"BK c #18185A5A7373",
+"CK c #10106B6B9C9C",	"DK c #10105A5A8484",	"EK c #08087B7B6363",
+"FK c #08085A5A7B7B",	"GK c #00006B6B9C9C",	"HK c #000063637B7B",
+"IK c #00005A5A8C8C",
+/* pixels */
+"CJAHAHAHAHHILHLHBHLHLJNHNHNHGINHGINHGINHGINHGINHGINHGINHGINHGIKJ",
+"AHAAAAAAAGHDABBBGCBFBFHCPCOCEEHDJDEEJDEEHDJDEEHDJDEEJDEEHDEEJDNH",
+"AHAAAGAAABABABKEOCHCHCPCFEFEABAEHDFCDDJDDDMCJDHDFCHDHDGCDDJDDDLH",
+"EGAEDDABOAABOCEGHCHCPCHCBHJDJDEEJDEEJDEEJDAEJDEEAEJDEEJDEEJDEELH",
+"AHAAAAAAMCJDGCABHCHCBFOCPCJDEEJDEEJDEEAEEEEEAEJDEEFEFEFEEEEEJDGI",
+"AHAAAAPAAGGCABBBMCEGJDNCPCPCEEEEEEEEEEEEEEJDEEEEFEDIPIGFFEFEEENH",
+"EGOAKEAAABPAABKEHCHCHCHCMEBFABJDAEMCOCEEMCMCFEOCDDLEKHIDIDEEDDLH",
+"LHAEMCAAABABAEIFHCHCHCPCBHOCKEKEEEFEEEFEEEFEEEKEBFGEDIKFMEFEEEGI",
+"AHAAAAABGCJDABGCBBOCHGHCPCMDEEFEKEEEFEKEFEKEEEMEBFJFDIGEIFBFFEGI",
+"AHAAAAPAAHGCABBBMCJFMDOCPCJDMEKEKEMEKEKEKEKEMEIFGEFGEIIGJFGEMEGI",
+"AHAAAEAAABABGCNBDBOCNCNCMDEEMCEEEEMCJDKEDDDDLFCIDIEIPICIDIDIJDNH",
+"AHKEDDAAPAABOCKFPBICNCPCHGFEMEMEMEMEHFMEMEIFJFJELCCDCGBBCDLIIGHI",
+"EGAAAAABABJDMBNCPBADGENCMDMDMEHFIFHFMEHFIFMECHJEPCLDBGGDGDLIIGDJ",
+"AHAAAAAAAHEDKAOBEBBDCEODICMDIFIFMEIFIFIFIFIFCHEFLDPDOGGDPDMIFHHI",
+"AHAAOCABMBEABABAFABABAGBNELEHDKEHFDDEEIFJDEEFGCGLDPDPGPDPDAJMFHI",
+"AHDDEGABBBEABACAFABACBGBFHGEIFGGIFGGIFIFGGIFDHCGJEMHFIAFAFBJDHII",
+"AHAAAAABMBEAHAEAEADACABDODBEHGIFGGIFHGGGIFHGCHJHAFAFEFAFFFFJDHMJ",
+"AHAAAAAABEIADADAKACADAGBODNEGGHGIEIENFGGHGGGOHDGFFFFFFFFFFAJOHHI",
+"AHAAABABPCGAKADADAKADAFDODMFHIHIAIPFIIIIHIHIEJCIFFDGFFDGDGJJFJCK",
+"AHAAAHHCMBGAEAEAEAFAFAJCLGFKPEPEPEKDPEPEOIIKHKLIDGDGPGDGIHEKIKGK",
+"EGFCDDAANCJAIAIAIAIAIANDBKOJJBLALALBLAMANGFKHKFIMHPGMHFILIEKFKGK",
+"LHAAAABBNCFBJAJAJAEBGBDFBKOJBCNADCDCIBHBNGBKAKFIMHMHMHMHMHEKHKGK",
+"AHAAAAABADEBJCEBGBACACHEBKNIBCJBJBHBJBJBHHOJJJPIIHPGIHIHIHPJDKGK",
+"AHAAOCJDNCEBOBACOBOBOBHEEJNIKCLBKBBCKBCCKGHJJJMHDGIHPGDGIHEKEJCK",
+"AHAAKEABMBEBDBDBOBOBOBHENIAIKCDCDCDCDCECKGKIGJCIDGFFLGDGDGPJNJMJ",
+"CJAAOAABBBIADBHADBHAKAHEAIBIDCDCBCCCDCCCPFKIJIPGBGCFDGFFDGIJIIMJ",
+"AHAAAAABMBIABADBBAHAHAHEAIGHKCJBBCKBKBBCKGPHJIPGFFGFFFFFFFIJJILJ",
+"AHAAAAABMDFDFDBDFDNDBDHEFHJGDEDEDEDEOEDEOFPHMGBJBJAJBJBJBJMIOHDJ",
+"EGAAAAJDHGNFFHMGFHJGMGEHJGNFNFMGMGMGMGMGLGJGCHEHFHPHMGOHPHFHIGDJ",
+"LHAAOCIFIFIFLFLFMFMFJFLFIFJFHGIGMFIGNFMFMFLFIFLFHGIGFGIGIGHGJFCJ",
+"EGDDKEKEMEBFBFBFBFMEBFBFFEKEMEMEMEGEBFMEBFBFBFKEMEBFMEBFBFKEKEGI",
+"KJLHGINHGINHNHNHNHGINHNHGINHGINHNHGIGINHGINHNHGINHNHGIGINHNHGICJ"};
+
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+const 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.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#if QT_VERSION >= 0x040000
+BitMapQT::BitMapQT(GraphObj *g, QMainWindow *wi, int vr, int hr):anyOutput()
+{
+	int w, h;
+
+	hres = (double)hr;		vres = (double)vr;
+	image = 0L;			hgo = 0L;
+	dlgwidget = 0L;			widget = wi;
+	ShowObj = ShowAnimated = 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);
+	qPen.setJoinStyle(Qt::RoundJoin);
+	qPainter.setPen(qPen);
+	qFont = qPainter.font();
+}
+#endif
+
+BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput()
+{
+	int w, h;
+
+	hres = (double)hr;		vres = (double)vr;
+	image = 0L;			hgo = 0L;			
+	dlgwidget = wi;			widget = 0L;
+	ShowObj = ShowAnimated = 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);
+	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;			widget = 0L;
+	w = abs(w);		h = abs(h);			ShowObj = ShowAnimated = 0L;
+	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(ShowObj) delete((eph_obj*)ShowObj);	ShowObj = 0L;
+	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(ShowObj) {
+		delete((eph_obj*)ShowObj);	ShowObj = 0L;
+		}
+	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(ShowObj) {
+		delete((eph_obj*)ShowObj);	ShowObj = 0L;
+		}
+	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(ShowObj) {
+		delete((eph_obj*)ShowObj);	ShowObj = 0L;
+		}
+	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;
+#if QT_VERSION < 0x040000
+	bitBlt(mempic, x, y, src->mempic, sx, sy, sw, sh, invert ? Qt::NotCopyROP : Qt::CopyROP);
+#else
+	if(invert) {
+		QImage qi = src->mempic->copy(sx, sy, sw, sh).toImage();
+		qi.invertPixels();
+		qPainter.drawImage(x, y, qi);
+		}
+	else qPainter.drawPixmap(x, y, *src->mempic, sx, sy, sw, sh);
+#endif
+	return true;
+}
+
+bool
+BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+bool
+BitMapQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+bool
+BitMapQT::oGetPix(int x, int y, DWORD *col)
+{
+	DWORD pix;
+
+#if QT_VERSION < 0x040000
+	if(!image && !(image = new QImage(mempic->convertToImage())))return false;
+#else
+	if(!image && !(image = new QImage(mempic->toImage())))return false;
+#endif
+	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)
+{
+	const char** xpm_data;
+
+	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) {
+#if QT_VERSION < 0x040000
+		QPixmap pm;
+
+		QImage image(xpm_data);
+		pm.convertFromImage(image);
+		bitBlt(mempic, x, y, &pm, 0, 0,	-1, -1, Qt::CopyROP);
+#else
+		QPixmap pm(xpm_data);
+		qPainter.drawPixmap(x, y, pm);
+#endif
+		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 {
+		for (i = 1; i < cp; i++)qPainter.drawLine(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);
+		}
+	return true;
+}
+
+bool
+BitMapQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+#if QT_VERSION < 0x040000
+	qPainter.drawRect(x1, y1, x2-x1, y2-y1);
+#else
+	qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+#endif
+	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;
+	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+BitMapQT::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+	int i;
+
+#if QT_VERSION < 0x040000
+	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;
+		}
+#else
+	QPoint *a;
+
+	if(a = (QPoint*)malloc(cp * sizeof(QPoint))) {
+		for(i = 0; i < cp; i++) {
+			a[i].setX(pts[i].x);	a[i].setY(pts[i].y);
+			}
+		qPainter.drawPolygon(a, cp);
+		free(a);
+		}
+#endif
+	if(hgo) hgo->oPolygon(pts, cp);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process a menu event
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void ToolMenu(GraphObj *b, anyOutput *o, int tm)
+{
+	if(b && o) b->Command(CMD_TOOLMODE, (void*)(& tm), o);
+}
+
+bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj)
+{
+	PrintQT *out;
+
+	if(OutputClass) Undo.SetDisp(OutputClass);
+	if(parent && (parent->y() || parent->x())) {
+		CurrWidgetPos.x = parent->x();		CurrWidgetPos.y = parent->y();		CurrWidget = parent;
+		}
+	if(BaseObj) switch(id) {
+	case CM_OPEN:
+		BaseObj->Command(CMD_OPEN, 0L, OutputClass);		return true;
+	case CM_SAVEDATA:
+		BaseObj->Command(CMD_SAVEDATA, 0L, OutputClass);	return true;
+	case CM_SAVEDATAAS:
+		BaseObj->Command(CMD_SAVEDATAAS, 0L, OutputClass);	return true;
+	case CM_INSROW:
+		BaseObj->Command(CMD_INSROW, 0L, OutputClass);		return true;
+	case CM_INSCOL:
+		BaseObj->Command(CMD_INSCOL, 0L, OutputClass);		return true;
+	case CM_DELROW:
+		BaseObj->Command(CMD_DELROW, 0L, OutputClass);		return true;
+	case CM_DELCOL:
+		BaseObj->Command(CMD_DELCOL, 0L, OutputClass);		return true;
+	case CM_SAVEGRAPHAS:
+		SaveGraphAs(BaseObj);					return true;
+	case CM_EXPORT:
+		if(OutputClass) {
+			OutputClass->HideMark();	OpenExportName(BaseObj, 0L);
+			}
+		BaseObj->DoPlot(0L);					return true;
+	case CM_REDRAW:
+		if(OutputClass && OutputClass->Erase(defs.Color(COL_BG))) {
+			CurrGO=0L;		OutputClass->HideMark();
+			BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
+			}
+		BaseObj->DoPlot(0L);					return true;
+	case CM_UPDATE:
+		BaseObj->Command(CMD_UPDATE, 0L, OutputClass);		return true;
+	case CM_LAYERS:
+		BaseObj->Command(CMD_LAYERS, 0L, OutputClass);		return true;
+	case CM_ADDPLOT:
+		BaseObj->Command(CMD_ADDPLOT, 0L, OutputClass);		return true;
+	case CM_ADDAXIS:
+		BaseObj->Command(CMD_ADDAXIS, 0L, OutputClass);		return true;
+	case CM_LEGEND:
+		BaseObj->Command(CMD_LEGEND, 0L, OutputClass);		return true;
+	case CM_DELOBJ:
+		if(OutputClass && 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!");
+		return true;
+	case CM_PRINT:
+		if(!BaseObj) return false;
+		out = new PrintQT(0L, 0L);
+#if QT_VERSION >= 0x030000				//Qt version 3, n.a. in version 2
+//		int m = iround(out->hres/60.0);
+//		out->printer->setMargins(m, m, m, m);
+#endif
+		if(BaseObj->Id == GO_SPREADDATA) {
+			BaseObj->Command(CMD_PRINT, 0L, out);
+			}
+		else if(out->StartPage()){
+			BaseObj->DoPlot(out);
+			out->EndPage();
+			}
+		BaseObj->DoPlot(OutputClass);
+		delete out;						return true;
+	case CM_ADDROWCOL:
+		BaseObj->Command(CMD_ADDROWCOL, 0L, OutputClass);	return true;
+	case CM_FILLRANGE:
+		BaseObj->Command(CMD_FILLRANGE, 0L, OutputClass);	return true;
+	case CM_NEWGRAPH:
+		BaseObj->Command(CMD_NEWGRAPH, 0L, OutputClass);	return true;
+	case CM_NEWPAGE:
+		BaseObj->Command(CMD_NEWPAGE, 0L, OutputClass);		return true;
+	case CM_DELGRAPH:
+		BaseObj->Command(CMD_DELGRAPH, 0L, OutputClass);	return true;
+	case CM_DEFAULTS:
+		BaseObj->Command(CMD_CONFIG, 0L, OutputClass);		return true;
+	case CM_REPANOV:
+		rep_anova(BaseObj, BaseObj->data);			return true;
+	case CM_REPKRUSKAL:
+		rep_kruskal(BaseObj, BaseObj->data);			return true;
+	case CM_REPTWANR:
+		rep_twoway_anova(BaseObj, BaseObj->data);		return true;
+	case CM_REPTWANOV:
+		rep_twanova(BaseObj, BaseObj->data);			return true;
+	case CM_REPFRIEDM:
+		rep_fmanova(BaseObj, BaseObj->data);			return true;
+	case CM_CORRELM:
+		rep_correl(BaseObj, BaseObj->data, 0);			return true;
+	case CM_CORRELT:
+		rep_correl(BaseObj, BaseObj->data, 1);			return true;
+	case CM_SMPLSTAT:
+		rep_samplestats(BaseObj, BaseObj->data);		return true;
+	case CM_REPCMEANS:
+		rep_compmeans(BaseObj, BaseObj->data);			return true;
+	case CM_REPTWOWAY:
+		rep_twowaytable(BaseObj, BaseObj->data);		return true;
+	case CM_REPREGR:
+		rep_regression(BaseObj, BaseObj->data);			return true;
+	case CM_ROBUSTLINE:
+		rep_robustline(BaseObj, BaseObj->data);			return true;
+	case CM_ABOUT:
+		RLPlotInfo();						return true;
+	case CM_FILE1:
+		((RLPwidget*)parent)->openHistoryFile(0);		return true;
+	case CM_FILE2:
+		((RLPwidget*)parent)->openHistoryFile(1);		return true;
+	case CM_FILE3:
+		((RLPwidget*)parent)->openHistoryFile(2);		return true;
+	case CM_FILE4:
+		((RLPwidget*)parent)->openHistoryFile(3);		return true;
+	case CM_FILE5:
+		((RLPwidget*)parent)->openHistoryFile(4);		return true;
+	case CM_FILE6:
+		((RLPwidget*)parent)->openHistoryFile(5);		return true;
+	case CM_EXIT:
+		if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){
+			if(BaseObj->parent) BaseObj->parent->Command(CMD_DELOBJ, BaseObj, 0L);
+			else if(BaseObj->Id == GO_SPREADDATA) QAppl->exit(0);
+			}
+		return true;
+	case CM_COPY:	case CM_CUT:	case CM_COPYGRAPH:
+		EmptyClip();
+		if(CurrGO && BaseObj->Id != GO_SPREADDATA) {
+			if(CurrGO->Id == GO_POLYLINE || CurrGO->Id == GO_POLYGON || CurrGO->Id == GO_RECTANGLE
+				|| CurrGO->Id == GO_ROUNDREC || CurrGO->Id == GO_ELLIPSE || CurrGO->Id == GO_BEZIER) {
+				if(OutputClass) ShowCopyMark(OutputClass, &CurrGO->rDims, 1);
+				CopyData(CurrGO);					return true;
+				}
+			else if(CurrGO->Id == GO_TEXTFRAME) {
+				if(CurrGO->Command(CMD_COPY, 0L, OutputClass))	return true;
+				}
+			}	
+		if(BaseObj->Id == GO_SPREADDATA && BaseObj->Command(id == CM_CUT ? CMD_CUT : CMD_QUERY_COPY, 0L, OutputClass)) {
+			CopyData(BaseObj);
+			}
+		else if(id == CM_CUT) return true;
+		else if(BaseObj->Id == GO_PAGE) {
+			if(CurrGraph) {
+				if(OutputClass) ShowCopyMark(OutputClass, &CurrGraph->rDims, 1);
+				CopyGraph(CurrGraph);
+				}
+			}
+		else if(CurrGraph && CurrGraph->Id == GO_GRAPH){
+			if(OutputClass) ShowCopyMark(OutputClass, &CurrGraph->rDims, 1);
+			CopyGraph(CurrGraph);
+			}
+		else if(BaseObj->Id == GO_GRAPH) {
+			if(OutputClass) ShowCopyMark(OutputClass, &BaseObj->rDims, 1);
+			CopyGraph(BaseObj);
+			}
+		return true;
+	case CM_ZOOMIN:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"+"), OutputClass);		return true;
+	case CM_ZOOMOUT:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"-"), OutputClass);		return true;
+	case CM_ZOOMFIT:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"fit"), OutputClass);	return true;
+	case CM_ZOOM25:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"25"), OutputClass);	return true;
+	case CM_ZOOM50:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"50"), OutputClass);	return true;
+	case CM_ZOOM100:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"100"), OutputClass);	return true;
+	case CM_ZOOM200:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"200"), OutputClass);	return true;
+	case CM_ZOOM400:
+		BaseObj->Command(CMD_ZOOM, (void*)(&"400"), OutputClass);	return true;
+	case CM_T_STANDARD:
+		HideCopyMark();
+		ToolMenu(BaseObj, OutputClass, TM_STANDARD);			return true;
+	case CM_T_DRAW:
+		ToolMenu(BaseObj, OutputClass, TM_DRAW);			return true;
+	case CM_T_POLYLINE:
+		ToolMenu(BaseObj, OutputClass, TM_POLYLINE);			return true;
+	case CM_T_POLYGON:
+		ToolMenu(BaseObj, OutputClass, TM_POLYGON);			return true;
+	case CM_T_RECTANGLE:
+		ToolMenu(BaseObj, OutputClass, TM_RECTANGLE);			return true;
+	case CM_T_ROUNDREC:
+		ToolMenu(BaseObj, OutputClass, TM_ROUNDREC);			return true;
+	case CM_T_ELLIPSE:
+		ToolMenu(BaseObj, OutputClass, TM_ELLIPSE);			return true;
+	case CM_T_ARROW:
+		ToolMenu(BaseObj, OutputClass, TM_ARROW);			return true;
+	case CM_T_TEXT:
+		ToolMenu(BaseObj, OutputClass, TM_TEXT);			return true;
+	}
+
+	return false;
+} 
+
+#if QT_VERSION < 0x040000
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The menu class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RLPmenu::RLPmenu(QWidget *par, anyOutput *o, GraphObj *g)
+:QMenuBar(par)
+{
+	parent = par;		OutputClass = o;		BaseObj = g;
+	connect(this, SIGNAL(activated(int)), this, SLOT(doMenuItem(int)));
+}
+
+void
+RLPmenu::doMenuItem(int id)
+{
+	ProcMenuEvent(id, parent, OutputClass, BaseObj);
+}
+#else		//Qt version >= 4.0
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Menu item
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RLPaction::RLPaction(QWidget *par, anyOutput *o, GraphObj *g, char *name, int id):QAction(name, par)
+{
+	Id = id;	OutputClass = o;	BaseObj = g;	parent = par;
+	connect(this, SIGNAL(triggered()), this, SLOT(doMenuItem()));
+	switch(id) {
+	case CM_FILE1:
+		((OutputQT*)o)->itFil1 = this;
+		setVisible(false);		break;
+	case CM_FILE2:
+		((OutputQT*)o)->itFil2 = this;
+		setVisible(false);		break;
+	case CM_FILE3:
+		((OutputQT*)o)->itFil3 = this;
+		setVisible(false);		break;
+	case CM_FILE4:
+		((OutputQT*)o)->itFil4 = this;
+		setVisible(false);		break;
+	case CM_FILE5:
+		((OutputQT*)o)->itFil5 = this;
+		setVisible(false);		break;
+	case CM_FILE6:
+		((OutputQT*)o)->itFil6 = this;
+		setVisible(false);		break;
+	case CM_T_STANDARD:
+		((OutputQT*)o)->ittStd = this;
+		setCheckable(true);		break;
+	case CM_T_DRAW:
+		((OutputQT*)o)->ittDraw = this;
+		setCheckable(true);		break;
+	case CM_T_POLYLINE:
+		((OutputQT*)o)->ittPl = this;
+		setCheckable(true);		break;
+	case CM_T_POLYGON:
+		((OutputQT*)o)->ittPg = this;
+		setCheckable(true);		break;
+	case CM_T_RECTANGLE:
+		((OutputQT*)o)->ittRec = this;
+		setCheckable(true);		break;
+	case CM_T_ROUNDREC:
+		((OutputQT*)o)->ittRrec = this;
+		setCheckable(true);		break;
+	case CM_T_ELLIPSE:
+		((OutputQT*)o)->ittElly = this;
+		setCheckable(true);		break;
+	case CM_T_ARROW:
+		((OutputQT*)o)->ittArr = this;
+		setCheckable(true);		break;
+	case CM_T_TEXT:
+		((OutputQT*)o)->ittTxt = this;
+		setCheckable(true);		break;
+	}
+}
+
+void
+RLPaction::doMenuItem()
+{
+	if(ProcMenuEvent(Id, parent, OutputClass, BaseObj)) return;
+}
+
+#endif
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The display output class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#if QT_VERSION < 0x040000
+OutputQT::OutputQT(GraphObj *g):BitMapQT(g, (QWidget*)0L)
+#else
+OutputQT::OutputQT(GraphObj *g):BitMapQT(g, (QMainWindow*)0L)
+#endif
+{
+	int w, h;
+
+	HScroll = VScroll = 0L;
+	GetDesktopSize(&w, &h);
+	CreateNewWindow(BaseObj = g);
+	if(widget) {
+		if(CurrWidgetPos.x >= ((w>>1)-100))CurrWidgetPos.x = CurrWidgetPos.y = 50;
+		widget->show();
+		widget->move(CurrWidgetPos.x+=50, CurrWidgetPos.y+=50);
+		if(widget->x() || widget->y()) {
+			CurrWidgetPos.x = widget->x();	CurrWidgetPos.y = widget->y();
+			}
+		}
+#if QT_VERSION >= 0x040000
+	itFil1 = itFil2 = itFil3 = itFil4 = itFil5 = itFil6 = 0L;
+	ittStd = ittDraw = ittPl = ittPg = ittRec = ittRrec = ittElly = ittArr = ittTxt = 0L;
+#endif
+}
+
+OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
+{
+	//assume fixed size (dialog) widget
+	if(dlgwidget = wi) {
+		wi->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
+		}
+	HScroll = VScroll = 0L;			BaseObj = 0L;
+	wi->OutputClass = this;
+	wi->mempic = mempic;
+	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;
+		if(widget) {
+			rc->bottom = widget->height() - MenuHeight-6;
+			rc->right = widget->width();
+			}
+		else if(dlgwidget) {
+			rc->bottom = dlgwidget->height() - MenuHeight-6;
+			rc->right = dlgwidget->width();
+			}
+		if(rc->bottom < 10 && rc->right < 10) {
+			rc->right = 600;	rc->bottom = 400;
+			}
+		return (rc->right > 40 && rc->bottom > 40);
+		}
+	return false;
+}
+
+void
+OutputQT::Caption(char *txt)
+{
+	QString cap(txt);
+#if QT_VERSION < 0x040000
+	if(widget) widget->setCaption(cap);
+	else if(dlgwidget) dlgwidget->setCaption(cap);
+#else
+	if(widget) widget->setWindowTitle(cap);
+	else if(dlgwidget) dlgwidget->setWindowTitle(cap);
+#endif
+}
+
+#if QT_VERSION < 0x040000
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+const static 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};
+
+#else
+
+const static char* hand_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+".......11.......",	"...110100111....",
+"..10011001001...",	"..1001100100101.",
+"...1001001001101",	"...1001001001001",
+".110100000001001",	"1001100000000001",
+"100010000000001.",	".10000000000001.",
+".10000000000001.",	"..100000000001..",
+"...10000000001..",	"....100000001...",
+".....10000001...",	".....10000001..."};
+
+const static char* zoom_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"................",	"................",
+".......111......",	".....11...11....",
+"....1.......1...",	"...1....1....1..",
+"...1....1....1..",	"..1.....0.....1.",
+"..1..1100011..1.",	"..1.....0.....1.",
+"...1....1....1..",	"...1....1....1..",
+"....1.......1...",	".....11...11....",
+".......111......",	"................"};
+
+
+const static char* drawpen_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"11..............",	"1111............",	
+".11111..........",	".1110011........",
+"..1000001.......",	"..10001001......",
+"...10001001.....",	"...100001001....",
+"....100001001...",	".....100001001..",
+"......100001001.",	".......100001011",
+"........10000111",	".........100111.",
+"..........1111..",	"...........11..."};
+
+const static char* paste_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"..1.............",	"..1.............",
+"11111...........",	"..1.............",
+"..1...111111111.",	".....10000000101",
+".....10100000101",	".....10111111001",
+".....10000000001",	".....10000000001",
+".....10000000001",	".....10000000001",
+".....10000000001",	".....10000000001",
+"......111111111.",	"................"};
+
+const static char* drect_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"..1.............",	"..1.............",
+"11111...........",	"..1.............",
+"..1.............",	"................",
+"...1111111111111",	"...1000000000001",
+"...1000000000001",	"...1000000000001",
+"...1000000000001",	"...1000000000001",
+"...1000000000001",	"...1000000000001",
+"...1111111111111",	"................"};
+
+const static char* drrect_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"..1.............",	"..1.............",
+"11111...........",	"..1.............",
+"..1.............",	"................",
+".....111111111..",	"....10000000001.",
+"...1000000000001",	"...1000000000001",
+"...1000000000001",	"...1000000000001",
+"...1000000000001",	"....10000000001.",
+".....111111111..",	"................"};
+
+const static char* delly_xpm[] = {
+"16 16 3 1",		". c None",
+"1 c #000000",		"0 c #ffffff",
+"..1.............",	"..1.............",
+"11111...........",	"..1.............",
+"..1.............",	"................",
+".......11111....",	".....110000011..",
+"....10000000001.",	"...1000000000001",
+"...1000000000001",	"...1000000000001",
+"....10000000001.",	".....110000011..",
+".......11111....",	"................"};
+
+#endif
+
+//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);
+	printf("\n%s\n", txt);
+}
+*/
+
+void
+OutputQT::MouseCursor(int cid, bool force)
+{
+	if(cid == cCursor && !force) return;
+	if(cid == MC_LAST) cid = cCursor;
+#if QT_VERSION < 0x040000
+	QBitmap *bits, *mask;
+	bits = mask = 0L;
+#endif
+
+	if(widget)CurrWidget = widget;
+	else if(dlgwidget) CurrWidget = dlgwidget;
+	if(widget) switch(cid) {
+#if QT_VERSION >= 0x030000				//Qt version 3
+	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
+	case MC_TXTFRM:
+	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_COLWIDTH:
+	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_TXTFRM:
+	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_COLWIDTH:
+	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:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, hand_bits, TRUE);
+		mask = new QBitmap(16, 16, hand_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 7, 7));
+#else
+		widget->setCursor(QCursor(QPixmap(hand_xpm), 7, 7));
+#endif
+		break;
+	case MC_ZOOM:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, zoom_bits, TRUE);
+		mask = new QBitmap(16, 16, zoom_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 7, 7));
+#else
+		widget->setCursor(QCursor(QPixmap(zoom_xpm), 7, 7));
+#endif
+		break;
+	case MC_PASTE:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, paste_bits, TRUE);
+		mask = new QBitmap(16, 16, paste_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 2, 2));
+#else
+		widget->setCursor(QCursor(QPixmap(paste_xpm), 2, 2));
+#endif
+		break;
+	case MC_DRAWPEN:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, drawpen_bits, TRUE);
+		mask = new QBitmap(16, 16, drawpen_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 0, 0));
+#else
+		widget->setCursor(QCursor(QPixmap(drawpen_xpm), 0, 0));
+#endif
+		break;
+	case MC_DRAWREC:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, drect_bits, TRUE);
+		mask = new QBitmap(16, 16, drect_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 2, 2));
+#else
+		widget->setCursor(QCursor(QPixmap(drect_xpm), 0, 0));
+#endif
+		break;
+	case MC_DRAWRREC:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, drrect_bits, TRUE);
+		mask = new QBitmap(16, 16, drrect_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 2, 2));
+#else
+		widget->setCursor(QCursor(QPixmap(drrect_xpm), 0, 0));
+#endif
+		break;
+	case MC_DRAWELLY:
+#if QT_VERSION < 0x040000
+		bits = new QBitmap(16, 16, delly_bits, TRUE);
+		mask = new QBitmap(16, 16, delly_mask, TRUE);
+		widget->setCursor(QCursor(*bits, *mask, 2, 2));
+#else
+		widget->setCursor(QCursor(QPixmap(delly_xpm), 0, 0));
+#endif
+		break;
+	default:	return;
+		}
+#if QT_VERSION < 0x040000
+	if(bits) delete bits;		if(mask) delete mask;
+#endif
+	cCursor = cid;
+}
+
+bool
+OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
+{
+	QScrollBar *sb;
+
+	if((CurrWidget = widget) && (widget->x() || widget->y())) {
+		CurrWidgetPos.x = widget->x();		CurrWidgetPos.y = widget->y();
+		}
+	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(ShowObj) {
+		delete((eph_obj*)ShowObj);	ShowObj = 0L;
+		}
+	if(widget)widget->repaint();
+	else if(dlgwidget)dlgwidget->repaint();
+	return true;
+}
+
+bool
+OutputQT::UpdateRect(RECT *rc, bool invert)
+{
+	int x1, x2, y1, y2;
+
+	if((!widget && !dlgwidget) || !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;
+#if QT_VERSION < 0x040000
+	if(widget) bitBlt(widget, x1, y1, mempic, x1, y1, x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP);
+	if(dlgwidget) bitBlt(dlgwidget, x1, y1, mempic, x1, y1, x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP);
+#else
+	if(widget)widget->update(rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top);
+	else if(dlgwidget)dlgwidget->update(rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top);
+	if(invert) {
+		ShowObj = new eph_invert((eph_obj*)ShowObj, mempic, rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top);
+		}
+#endif
+	return true;
+}
+
+void
+OutputQT::ShowLine(POINT * pts, int cp, DWORD color)
+{
+	int i;
+	RECT rec;
+
+	if(cp < 2) return;
+	rec.left = rec.right = pts[0].x;			rec.top = rec.bottom = pts[0].y;
+	for(i = 1; i < cp; i++) {
+		if(pts[i].x < rec.left) rec.left = pts[i].x;	if(pts[i].x > rec.right) rec.right = pts[i].x;
+		if(pts[i].y < rec.top) rec.top = pts[i].y;	if(pts[i].y > rec.bottom) rec.bottom = pts[i].y;
+		}
+	rec.left -= 2;		rec.top -= 2;		rec.bottom += 2;	rec.right += 2;
+	if(rec.bottom < 2 && rec.top < 2) return;
+	ShowObj = new eph_line((eph_line*)ShowObj, pts, cp, color);
+#if QT_VERSION >= 0x040000
+	UpdateRect(&rec, false);
+#else
+	QPainter qp(widget ? widget : dlgwidget);
+	((eph_obj*)ShowObj)->DoPlot(&qp);
+#endif
+}
+
+void
+OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
+{
+	RECT rec;
+
+	rec.left = rec.right = p1.x;			rec.top = rec.bottom = p1.y;
+	UpdateMinMaxRect(&rec, p2.x, p2.y);		IncrementMinMaxRect(&rec, 2);
+	if(rec.bottom < 2 && rec.top < 2) return;
+	ShowObj = new eph_ellipse((eph_obj*)ShowObj, p1, p2, color);
+#if QT_VERSION >= 0x040000
+	UpdateRect(&rec, false);
+#else
+	QPainter qp(widget ? widget : dlgwidget);
+	((eph_obj*)ShowObj)->DoPlot(&qp);
+#endif
+}
+
+#if QT_VERSION < 0x040000
+	#define RLP_MITEM(menu,par,o,go,txt,id) menu->insertItem(txt,id)
+	#define RLP_MSEPARATOR(menu) menu->insertSeparator();
+#else
+	#define RLP_MITEM(menu,par,o,go,txt,id) menu->addAction(new RLPaction(par,o,go,txt,id));
+	#define RLP_MSEPARATOR(menu) menu->addSeparator();
+#endif
+
+#if QT_VERSION < 0x040000
+static QPopupMenu *MkToolMenu(QPopupMenu *tools, QWidget *widget, OutputQT *o, GraphObj *go)
+{
+	tools->setCheckable(true);
+	tools->insertTearOffHandle();
+#else
+static QMenu *MkToolMenu(QMenu *tools, QWidget *widget, OutputQT *o, GraphObj *go)
+{
+	tools->setTearOffEnabled(TRUE);
+#endif
+	RLP_MITEM(tools, widget, o, go, "&Standard", CM_T_STANDARD);
+	RLP_MSEPARATOR(tools);
+	RLP_MITEM(tools, widget, o, go, "&Draw", CM_T_DRAW);
+	RLP_MITEM(tools, widget, o, go, "Poly&line", CM_T_POLYLINE);
+	RLP_MITEM(tools, widget, o, go, "Poly&gon", CM_T_POLYGON);
+	RLP_MITEM(tools, widget, o, go, "&Rectangle", CM_T_RECTANGLE);
+	RLP_MITEM(tools, widget, o, go, "r&ound Rect.", CM_T_ROUNDREC);
+	RLP_MITEM(tools, widget, o, go, "&Ellipse", CM_T_ELLIPSE);
+	RLP_MITEM(tools, widget, o, go, "&Arrow", CM_T_ARROW);
+	RLP_MITEM(tools, widget, o, go, "&Text", CM_T_TEXT);
+	return tools;
+}
+
+#if QT_VERSION < 0x040000
+static QPopupMenu *MkZoomMenu(QPopupMenu *zoom, QWidget *widget, OutputQT *o, GraphObj *go)
+{
+	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);
+#else
+static QMenu *MkZoomMenu(QMenu *zoom, QWidget *widget, OutputQT *o, GraphObj *go)
+{
+	zoom->setTearOffEnabled(TRUE);
+	zoom->addAction("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
+	zoom->addAction("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
+	zoom->addAction("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
+#endif
+	RLP_MSEPARATOR(zoom);
+	RLP_MITEM(zoom, widget, o, go, "25%", CM_ZOOM25);
+	RLP_MITEM(zoom, widget, o, go, "50%", CM_ZOOM50);
+	RLP_MITEM(zoom, widget, o, go, "100%", CM_ZOOM100);
+	RLP_MITEM(zoom, widget, o, go, "200%", CM_ZOOM200);
+	RLP_MITEM(zoom, widget, o, go, "400%", CM_ZOOM400);
+	return zoom;
+}
+
+bool
+OutputQT::SetMenu(int type)
+{
+	if(!widget) return false;
+	if(type == MENU_SPREAD){
+#if QT_VERSION < 0x040000
+		QPopupMenu *file = new QPopupMenu(widget);
+		QPopupMenu *edit = new QPopupMenu(widget);
+		QPopupMenu *stats = new QPopupMenu(widget);
+		QPopupMenu *graph = new QPopupMenu(widget);
+		QPopupMenu *about = new QPopupMenu(widget);
+#else
+		QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File"));
+		QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit"));
+		QMenu *stats = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Statistics"));
+		QMenu *graph = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Graph"));
+		QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
+#endif
+		RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
+		RLP_MITEM(file, widget, this, BaseObj, "&Save", CM_SAVEDATA);
+		RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEDATAAS);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "E&xit", CM_EXIT);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE1);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE2);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE3);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE4);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE5);
+		RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE6);
+
+#if QT_VERSION < 0x040000
+		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+#else
+		edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z);
+#endif
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Rows/Cols", CM_ADDROWCOL);
+#if QT_VERSION < 0x040000
+		QPopupMenu *insert = new QPopupMenu(widget);
+		RLP_MITEM(insert, widget, this, BaseObj, "&Rows", CM_INSROW);
+		RLP_MITEM(insert, widget, this, BaseObj, "&Columns", CM_INSCOL);
+		edit->insertItem("&Insert", insert);
+		QPopupMenu *Delete = new QPopupMenu(widget);
+		RLP_MITEM(Delete, widget, this, BaseObj, "&Rows", CM_DELROW);
+		RLP_MITEM(Delete, widget, this, BaseObj, "&Columns", CM_DELCOL);
+		edit->insertItem("&Delete", Delete);
+#else
+		QMenu *insert = edit->addMenu("&Insert");
+		RLP_MITEM(insert, widget, this, BaseObj, "&Rows", CM_INSROW);
+		RLP_MITEM(insert, widget, this, BaseObj, "&Columns", CM_INSCOL);
+		QMenu *Delete = edit->addMenu("&Delete");
+		RLP_MITEM(Delete, widget, this, BaseObj, "&Rows", CM_DELROW);
+		RLP_MITEM(Delete, widget, this, BaseObj, "&Columns", CM_DELCOL);
+#endif
+		RLP_MSEPARATOR(edit);
+#if QT_VERSION < 0x040000
+		edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY);
+		edit->insertItem("C&ut", widget, SLOT(cmCut()), Qt::CTRL + Qt::Key_X, CM_CUT);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+#else
+		edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C);
+		edit->addAction("C&ut", widget, SLOT(cmCut()), Qt::CTRL +Qt::Key_X);
+		edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V);
+#endif
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Fill Range", CM_FILLRANGE);
+
+		RLP_MITEM(stats, widget, this, BaseObj, "&Sample Stats", CM_SMPLSTAT);
+		RLP_MITEM(stats, widget, this, BaseObj, "&Comp. Means", CM_REPCMEANS);
+#if QT_VERSION < 0x040000
+		QPopupMenu *anov = new QPopupMenu(widget);
+		RLP_MITEM(anov, widget, this, BaseObj, "&One Way Anova", CM_REPANOV);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Kruskal Wallis", CM_REPKRUSKAL);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Two Way Anova", CM_REPTWANOV);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Friedman Anova", CM_REPFRIEDM);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Two Way /w Replica", CM_REPTWANR);
+		stats->insertItem("&Anova", anov);
+		QPopupMenu *regr = new QPopupMenu(widget);
+		RLP_MITEM(regr, widget, this, BaseObj, "&Linear Regression", CM_REPREGR);
+		RLP_MITEM(regr, widget, this, BaseObj, "&Robust Line-Fit", CM_ROBUSTLINE);
+		stats->insertItem("&Regression", regr);
+		QPopupMenu *corr = new QPopupMenu(widget);
+		RLP_MITEM(corr, widget, this, BaseObj, "Correlation &Matrix", CM_CORRELM);
+		RLP_MITEM(corr, widget, this, BaseObj, "Tiled &Plots", CM_CORRELT);
+		stats->insertItem("C&orrelations", corr);
+#else
+		QMenu *anov = stats->addMenu("&Anova");
+		RLP_MITEM(anov, widget, this, BaseObj, "&One Way Anova", CM_REPANOV);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Kruskal Wallis", CM_REPKRUSKAL);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Two Way Anova", CM_REPTWANOV);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Friedman Anova", CM_REPFRIEDM);
+		RLP_MITEM(anov, widget, this, BaseObj, "&Two Way /w Replica", CM_REPTWANR);
+		QMenu *regr = stats->addMenu("&Regression");
+		RLP_MITEM(regr, widget, this, BaseObj, "&Linear Regression", CM_REPREGR);
+		RLP_MITEM(regr, widget, this, BaseObj, "&Robust Line-Fit", CM_ROBUSTLINE);
+		QMenu *corr = stats->addMenu("C&orrelations");
+		RLP_MITEM(corr, widget, this, BaseObj, "Correlation &Matrix", CM_CORRELM);
+		RLP_MITEM(corr, widget, this, BaseObj, "Tiled &Plots", CM_CORRELT);
+#endif
+		RLP_MITEM(stats, widget, this, BaseObj, "&2x2 Table", CM_REPTWOWAY);
+
+		RLP_MITEM(graph, widget, this, BaseObj, "Create &Graph", CM_NEWGRAPH);
+		RLP_MITEM(graph, widget, this, BaseObj, "Create &Page", CM_NEWPAGE);
+		RLP_MITEM(graph, widget, this, BaseObj, "&Flush Graph(s)", CM_DELGRAPH);
+		RLP_MSEPARATOR(graph);
+		RLP_MITEM(graph, widget, this, BaseObj, "&Settings", CM_DEFAULTS);
+		RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT);
+#if QT_VERSION < 0x040000
+		menu = new RLPmenu(widget, this, BaseObj);
+		menu->insertItem("&File", file);		menu->insertItem("&Edit", edit);
+		menu->insertItem("&Statistics", stats);		menu->insertItem("&Graph", graph);
+		menu->insertItem("&?", about);
+#if QT_VERSION >= 0x030000				//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
+#endif
+		}
+	else if(type == MENU_GRAPH) {
+#if QT_VERSION < 0x040000
+		QPopupMenu *file = new QPopupMenu(widget);
+		QPopupMenu *edit = new QPopupMenu(widget);
+		QPopupMenu *displ = new QPopupMenu(widget);
+		QPopupMenu *plots = new QPopupMenu(widget);
+		QPopupMenu *about = new QPopupMenu(widget);
+#else
+		QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File"));
+		QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit"));
+		QMenu *displ = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Display"));
+		MkToolMenu(((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Tools")),  widget, this, BaseObj);
+		QMenu *plots = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Plots"));
+		QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
+#endif
+		RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
+		RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEGRAPHAS);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+		RLP_MITEM(file, widget, this, BaseObj, "&Export", CM_EXPORT);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "&Close", CM_EXIT);
+#if QT_VERSION < 0x040000
+		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+		edit->insertSeparator();
+		edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+#else
+		edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z);
+		edit->addSeparator();
+		edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C);
+		edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V);
+#endif
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Update Values", CM_UPDATE);
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Delete Object", CM_DELOBJ);
+		RLP_MITEM(displ, widget, this, BaseObj, "&Redraw", CM_REDRAW);
+#if QT_VERSION < 0x040000
+		displ->insertItem("&Zoom", MkZoomMenu(new QPopupMenu(widget),  widget, this, BaseObj));
+#else
+		MkZoomMenu(displ->addMenu("&Zoom"),  widget, this, BaseObj);
+#endif
+		RLP_MITEM(displ, widget, this, BaseObj, "&Layers", CM_LAYERS);
+
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Plot", CM_ADDPLOT);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Axis", CM_ADDAXIS);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Legend", CM_LEGEND);
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(plots, widget, this, BaseObj, "&Configure", CM_DEFAULTS);
+		RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT);
+#if QT_VERSION < 0x040000
+		menu = new RLPmenu(widget, this, BaseObj);
+		menu->insertItem("&File", file);
+		menu->insertItem("&Edit", edit);
+		menu->insertItem("&Display", displ);
+		menu->insertItem("&Tools", MkToolMenu(new QPopupMenu(widget), widget, this, BaseObj));
+		menu->insertItem("&Plots", plots);
+		menu->insertItem("&?", about);
+#endif
+		}
+	else if(type == MENU_PAGE) {
+#if QT_VERSION < 0x040000
+		QPopupMenu *file = new QPopupMenu(widget);
+		QPopupMenu *edit = new QPopupMenu(widget);
+		QPopupMenu *displ = new QPopupMenu(widget);
+		QPopupMenu *plots = new QPopupMenu(widget);
+		QPopupMenu *about = new QPopupMenu(widget);
+#else
+		QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File"));
+		QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit"));
+		QMenu *displ = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Display"));
+		MkToolMenu(((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Tools")),  widget, this, BaseObj);
+		QMenu *plots = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Plots"));
+		QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
+#endif
+		RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
+		RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEGRAPHAS);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+		RLP_MITEM(file, widget, this, BaseObj, "&Export", CM_EXPORT);
+		RLP_MSEPARATOR(file);
+		RLP_MITEM(file, widget, this, BaseObj, "&Close", CM_EXIT);
+
+#if QT_VERSION < 0x040000
+		edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+		edit->insertSeparator();
+		edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY);
+		edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+#else
+		edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z);
+		edit->addSeparator();
+		edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C);
+		edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V);
+#endif
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Update Values", CM_UPDATE);
+		RLP_MSEPARATOR(edit);
+		RLP_MITEM(edit, widget, this, BaseObj, "&Delete Object", CM_DELOBJ);
+		RLP_MITEM(displ, widget, this, BaseObj, "&Redraw", CM_REDRAW);
+#if QT_VERSION < 0x040000
+		displ->insertItem("&Zoom", MkZoomMenu(new QPopupMenu(widget),  widget, this, BaseObj));
+#else
+		MkZoomMenu(displ->addMenu("&Zoom"),  widget, this, BaseObj);
+#endif
+		RLP_MITEM(displ, widget, this, BaseObj, "&Layers", CM_LAYERS);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Graph", CM_NEWGRAPH);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Plot", CM_ADDPLOT);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Axis", CM_ADDAXIS);
+		RLP_MITEM(plots, widget, this, BaseObj, "Add &Legend", CM_LEGEND);
+		RLP_MSEPARATOR(plots);
+		RLP_MITEM(plots, widget, this, BaseObj, "Page &Settings", CM_DEFAULTS);
+		RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT);
+#if QT_VERSION < 0x040000
+		menu = new RLPmenu(widget, this, BaseObj);
+		menu->insertItem("&File", file);
+		menu->insertItem("&Edit", edit);
+		menu->insertItem("&Display", displ);
+		menu->insertItem("&Tools", MkToolMenu(new QPopupMenu(widget), widget, this, BaseObj));
+		menu->insertItem("&Plots", plots);
+		menu->insertItem("&?", about);
+#endif
+		}
+	else return false;
+#if QT_VERSION < 0x040000
+	menu->show();
+	MenuHeight = menu->height();
+	widget->resize(widget->width()+8, widget->height()+8);
+#else
+	((RLPwidget*)widget)->menu_bar->show();
+	MenuHeight = ((RLPwidget*)widget)->menu_bar->height();
+	widget->resize(widget->width()+8, widget->height()+8);
+#endif
+	if(MenuHeight< 20) MenuHeight = 24;
+	return true;
+}
+#undef RLP_MITEM
+#undef RLP_MSEPARATOR
+
+void
+OutputQT::CheckMenu(int mid, bool check)
+{
+#if QT_VERSION < 0x040000
+	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);
+#else
+	switch(mid) {
+	case TM_STANDARD:	case CM_T_STANDARD:
+		if(ittStd) ittStd->setChecked(check);
+		break;
+	case TM_DRAW:		case CM_T_DRAW:
+		if(ittDraw) ittDraw->setChecked(check);
+		break;
+	case TM_POLYLINE:	case CM_T_POLYLINE:
+		if(ittPl) ittPl->setChecked(check);
+		break;
+	case TM_POLYGON:	case CM_T_POLYGON:
+		if(ittPg) ittPg->setChecked(check);
+		break;
+	case TM_RECTANGLE:	case CM_T_RECTANGLE:
+		if(ittRec) ittRec->setChecked(check);
+		break;
+	case TM_ROUNDREC:	case CM_T_ROUNDREC:
+		if(ittRrec) ittRrec->setChecked(check);
+		break;
+	case TM_ELLIPSE:	case CM_T_ELLIPSE:
+		if(ittElly) ittElly->setChecked(check);
+		break;
+	case TM_ARROW:		case CM_T_ARROW:
+		if(ittArr) ittArr->setChecked(check);
+		break;
+	case TM_TEXT:		case CM_T_TEXT:
+		if(ittTxt) ittTxt->setChecked(check);
+		break;
+		}
+#endif
+}
+
+void
+OutputQT::FileHistory()
+{
+	char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6};
+	int i, j, k;
+
+#if QT_VERSION >= 0x040000
+	if(defs.File1 && defs.File1[0]) {
+		itFil1->setText(defs.File1);
+		itFil1->setVisible(true);
+		}
+	QAction *file_history[] = {itFil1, itFil2, itFil3, itFil4, itFil5, itFil6};
+	for(i = 0; i < 6 && *history[i] && file_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++;
+		file_history[i]->setText(*history[i]+j);
+		file_history[i]->setVisible(true);
+		}
+	HistMenuSize = i;
+#else				//Qt 3.0, Qt 2.0
+	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);
+#if QT_VERSION >= 0x030000				//Qt version 3, n.a. in version 2
+		menu->setItemVisible(CM_FILE1+i, true);
+#endif
+		}
+	HistMenuSize = i;
+#endif
+}
+
+void
+OutputQT::CreateNewWindow(GraphObj *g)
+{
+	int w=0, h=0;
+
+	GetDesktopSize(&w, &h);
+	if(w < 10 && h < 10) {
+		w = 858;	h = 572;
+		}
+	if(widget = new RLPwidget(0, 0, this, g)) {
+#if QT_VERSION < 0x040000
+		widget->setCaption("OutputQT::CreateNewWindow");
+#else
+		widget->setWindowTitle("OutputQT::CreateNewWindow");
+#endif
+		widget->setGeometry(0, 0, (int)(w*0.7), (int)(h*0.7));
+		((RLPwidget*)widget)->mempic = mempic;
+		HScroll = ((RLPwidget*)widget)->HScroll;
+		VScroll = ((RLPwidget*)widget)->VScroll;
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common widget support
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#if QT_VERSION < 0x040000
+RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
+	: QWidget(par)
+#else
+RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
+	: QMainWindow(par)
+#endif
+{
+	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(Qt::Horizontal, this);
+	HScroll->setRange(0, 1000);
+#if QT_VERSION < 0x040000
+	HScroll->setSteps(1, 16);
+#else
+	HScroll->setSingleStep(1);
+	HScroll->setPageStep(16);
+#endif
+	connect(HScroll, SIGNAL(valueChanged(int)), SLOT(hScrollEvent(int)));
+	VScroll = new QScrollBar(Qt::Vertical, this);
+	VScroll->setRange(0, 1000);
+#if QT_VERSION < 0x040000
+	VScroll->setSteps(1, 16);
+#else
+	VScroll->setSingleStep(1);
+	VScroll->setPageStep(16);
+#endif
+	connect(VScroll, SIGNAL(valueChanged(int)), SLOT(vScrollEvent(int)));
+#if QT_VERSION < 0x040000
+	menu_bar = new RLPmenu(this, o, BaseObj);
+	if(!MainWidget) {
+		QAppl->setMainWidget(MainWidget = this);
+		}
+	setFocusPolicy(StrongFocus);
+	setKeyCompression(true);
+#else
+	menu_bar = menuBar();
+	if(!MainWidget) {
+		MainWidget = this;
+		}
+	setFocusPolicy(Qt::StrongFocus);
+	setAttribute(Qt::WA_KeyCompression, true);
+#endif
+	setMouseTracking(true);
+}
+
+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::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);
+		}
+}
+
+//protected: widget events
+void
+RLPwidget::paintEvent(QPaintEvent *range)
+{
+	QRect rc;
+	QPainter qpainter(this);
+
+	if(!mempic) return;
+	rc = range->rect();
+	qpainter.drawPixmap(rc.left(), rc.top(), *mempic, rc.left(), rc.top(), rc.width()+1, rc.height()+1);
+#if QT_VERSION >=0x040000
+	if(((OutputQT*)OutputClass)->ShowObj)((eph_obj*)(((OutputQT*)OutputClass)->ShowObj))->DoPlot(&qpainter);
+	if(((OutputQT*)OutputClass)->ShowAnimated)((eph_obj*)(((OutputQT*)OutputClass)->ShowAnimated))->DoPlot(&qpainter);
+#endif
+}
+
+void
+RLPwidget::resizeEvent(QResizeEvent *)
+{
+	CurrWidget = this;
+	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;
+			e->accept();
+			}
+		}
+	else e->accept();
+	if(this == MainWidget) QAppl->exit(0);
+}
+
+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();		CurrWidget = this;
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	if(mev.StateFlags |= MOUSE_LBDOWN) mouse_buttons_down |= 0x01;
+	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()};
+
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	mouse_buttons_down = 0;
+	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mouseMoveEvent(QMouseEvent *e)
+{
+	int i;
+	MouseEvent mev = {mouse_buttons_down, MOUSE_MOVE, e->x(), e->y()};
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	if(((OutputQT*)OutputClass)->ShowObj) {
+		delete((eph_obj*)((OutputQT*)OutputClass)->ShowObj);
+		((OutputQT*)OutputClass)->ShowObj = 0L;
+		}
+	if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::keyPressEvent(QKeyEvent *e)
+{
+	int i, c;
+	QChar qc;
+	w_char uc;
+	bool is_shifted;
+
+#if QT_VERSION < 0x040000
+	i = e->state();
+	is_shifted = ((i & Qt::ShiftButton) != 0);
+#else
+	i = e->modifiers();
+	is_shifted = ((i & Qt::ShiftModifier) != 0);
+#endif
+	CurrWidget = this;
+	if(x() || y()) {
+		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+		}
+	if(BaseObj) switch(c = e->key()) {
+#if QT_VERSION < 0x040000
+		case Qt::Key_Prior:
+#else
+		case Qt::Key_PageUp:
+#endif
+			if(is_shifted) BaseObj->Command(CMD_SHPGUP, 0L, OutputClass);
+			else BaseObj->Command(CMD_PAGEUP, 0L, OutputClass);
+			break;
+#if QT_VERSION < 0x040000
+		case Qt::Key_Next:
+#else
+		case Qt::Key_PageDown:
+#endif
+			if(is_shifted) BaseObj->Command(CMD_SHPGDOWN, 0L, OutputClass);
+			else BaseObj->Command(CMD_PAGEDOWN, 0L, OutputClass);
+			break;
+		case Qt::Key_Left:
+			if(is_shifted) BaseObj->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRLEFT, 0L, OutputClass);
+			break;
+		case Qt::Key_Right:
+			if(is_shifted) BaseObj->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRIGHT, 0L, OutputClass);
+			break;
+		case Qt::Key_Up:
+			if(is_shifted) BaseObj->Command(CMD_SHIFTUP, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRUP, 0L, OutputClass);
+			break;
+		case Qt::Key_Down:
+			if(is_shifted) BaseObj->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+			else BaseObj->Command(CMD_CURRDOWN, 0L, OutputClass);
+			break;
+		case Qt::Key_Delete:
+			BaseObj->Command(CMD_DELETE, 0L, OutputClass);
+			break;
+		case Qt::Key_Tab:
+			BaseObj->Command(CMD_TAB, 0L, OutputClass);
+			break;
+		case Qt::Key_Backtab:
+			BaseObj->Command(CMD_SHTAB, 0L, OutputClass);
+			break;
+		case Qt::Key_Home:
+			BaseObj->Command(CMD_POS_FIRST, 0L, OutputClass);
+			break;
+		case Qt::Key_End:
+			BaseObj->Command(CMD_POS_LAST, 0L, OutputClass);
+			break;
+		default:
+			QString kres = e->text();
+			for(i = 0; i < kres.length(); i++) {
+				qc = kres.at(i);	uc = qc.unicode();
+				if(uc == 3) break;
+				else if(uc == 27 && OutputClass) {
+					OutputClass->HideMark();
+					ProcMenuEvent(CM_T_STANDARD, this, OutputClass, BaseObj);
+					}
+				else if(uc == 22) cmPaste();
+				else if(uc == 26) cmUndo();
+				else if(uc > 255) BaseObj->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass);
+				else BaseObj->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass);
+				}
+			break;
+		}
+	e->accept();
+}
+
+void
+RLPwidget::focusInEvent(QFocusEvent *e)
+{
+	if(x() || y()) {
+		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+		}
+	CurrWidget = this;
+	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();
+		}
+	else {
+		ErrorBox("The selected file   \ndoes not exist!\n");
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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 QT_VERSION < 0x040000
+	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);
+#else
+	if(go && out)switch (m) {
+	case PdmWidth:
+		return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
+	case PdmHeight:
+		return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
+	case PdmWidthMM:
+		return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) *
+			Units[defs.cUnits].convert);
+	case PdmHeightMM:
+		return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) *
+			Units[defs.cUnits].convert);
+		}
+	return QPrinter::metric((QPaintDevice::PaintDeviceMetric)m);
+#endif
+}
+
+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 QT_VERSION >= 0x030000				//Qt version 3, n.a. in version 2
+	if(fileName && go) printer = new FileEPS(g, this);
+	else printer = new QPrinter(QPrinter::HighResolution);
+	hres = vres = (9.5*((double)printer->resolution()));
+#else
+	if(fileName && go) printer = new FileEPS(g, this);
+	else printer = new QPrinter();
+	hres = vres = (9.5*600.0);
+#endif
+	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 && rc) {
+#if QT_VERSION < 0x040000
+		QPaintDeviceMetrics dm(printer);	rc->top = rc->left = 0;
+		rc->bottom = dm.height() *10;		rc->right = dm.width() *10;
+#else
+		QRect qrc = printer->pageRect();	rc->top = rc->left = 0;
+		rc->bottom = qrc.height();		rc->right = qrc.width();
+#endif
+		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 QT_VERSION < 0x040000
+	if(printer->setup(0)){
+#else
+	QPrintDialog dialog(printer, 0L);
+	if (dialog.exec()){
+#endif
+		qPainter.begin(printer);
+		qPainter.setWorldMatrix(dxf, FALSE);
+		return bPrinting = true;
+		}
+	else return false;
+
+}
+
+bool
+PrintQT::EndPage()
+{
+#if QT_VERSION < 0x040000
+	qPainter.flush();
+#endif
+	qPainter.end();		bPrinting = false;
+	return true;
+}
+
+bool
+PrintQT::Eject()
+{
+	if(!bPrinting) return false;
+#if QT_VERSION < 0x040000
+	qPainter.flush();
+#endif
+	qPainter.end();			qPainter.begin(printer);
+	qPainter.setWorldMatrix(dxf, FALSE);
+	return true;
+}
+
+bool
+PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+bool
+PrintQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+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 {
+		for (i = 1; i < cp; i++)qPainter.drawLine(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);
+		}
+	return true;
+}
+
+bool
+PrintQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+#if QT_VERSION < 0x040000
+	qPainter.drawRect(x1, y1, x2-x1, y2-y1);
+#else
+	qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+#endif
+	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;
+	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+PrintQT::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+PrintQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+	int i;
+
+#if QT_VERSION < 0x040000
+	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;
+		}
+#else
+	QPoint *a;
+
+	if(a = (QPoint*)malloc(cp * sizeof(QPoint))) {
+		for(i = 0; i < cp; i++) {
+			a[i].setX(pts[i].x);	a[i].setY(pts[i].y);
+			}
+		qPainter.drawPolygon(a, cp);
+		free(a);
+		}
+#endif
+	if(hgo) hgo->oPolygon(pts, cp);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Find a suitable www browser and more initialization
+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);
+	//some more initialization: create application icon
+#if QT_VERSION >= 0x040000
+	QPixmap pm(RLPlot_xpm);
+	rlp_icon = new QIcon(pm);
+	QAppl->setWindowIcon(*rlp_icon);
+#endif
+
+#ifdef RLP_PORT
+	//clipboard info
+	sprintf(TmpTxt, "%s", getenv("USER"));
+	if(TmpTxt[0])cb_owner = strdup(TmpTxt);
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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)
+#if QT_VERSION < 0x030000				//n.a. in Qt version 2
+: QWidget(par, name, Qt::WType_Dialog)
+#elif QT_VERSION < 0x040000
+: QWidget(par, name, 0x0000002)
+#else		//Qt 4.0
+//: QWidget(par ? par : CurrWidget, Qt::Window)
+: QWidget(0L, Qt::Window)
+#endif
+{
+	parent = par;
+	dlg = d;
+#if QT_VERSION < 0x040000
+	setFocusPolicy(StrongFocus);
+#else
+	setFocusPolicy(Qt::StrongFocus);
+#endif
+}
+
+DlgWidget::~DlgWidget()
+{
+	if(OutputClass){
+		((OutputQT*)OutputClass)->widget=0L;
+		delete ((OutputQT*)OutputClass);
+		}
+}
+
+void
+DlgWidget::paintEvent(QPaintEvent *range)
+{
+	QRect rc;
+	QPainter qpainter(this);
+
+	rc = range->rect();
+	qpainter.drawPixmap(rc.left(), rc.top(), *mempic, rc.left(), rc.top(), rc.width()+1, rc.height()+1);
+#if QT_VERSION >=0x040000
+	if(((OutputQT*)OutputClass)->ShowObj)((eph_obj*)(((OutputQT*)OutputClass)->ShowObj))->DoPlot(&qpainter);
+	if(((OutputQT*)OutputClass)->ShowAnimated)((eph_obj*)(((OutputQT*)OutputClass)->ShowAnimated))->DoPlot(&qpainter);
+#endif
+}
+
+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)
+{
+	int i;
+	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
+
+	HideTextCursor();		CurrWidget = this;
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	if(mev.StateFlags |= MOUSE_LBDOWN) mouse_buttons_down |= 0x01;
+	if (dlg)dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::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()};
+
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	mouse_buttons_down = 0;
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mouseMoveEvent(QMouseEvent *e)
+{
+	int i;
+	MouseEvent mev = {mouse_buttons_down, MOUSE_MOVE, e->x(), e->y()};
+
+#if QT_VERSION < 0x040000
+	i = e->state();
+	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
+#else
+	i = e->modifiers();
+	if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
+	if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
+#endif
+	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::keyPressEvent(QKeyEvent *e)
+{
+	int i, c;
+	QChar qc;
+	w_char uc;
+	bool is_shifted;
+
+#if QT_VERSION < 0x040000
+	i = e->state();
+	is_shifted = ((i & Qt::ShiftButton) != 0);
+#else
+	i = e->modifiers();
+	is_shifted = ((i & Qt::ShiftModifier) != 0);
+#endif
+	CurrWidget = this;
+	if(x() || y()) {
+		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+		}
+	if(dlg) switch(c = e->key()) {
+		case Qt::Key_Left:
+			if(is_shifted) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+			else dlg->Command(CMD_CURRLEFT, 0L, OutputClass);
+			break;
+		case Qt::Key_Right:
+			if(is_shifted) dlg->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+			else dlg->Command(CMD_CURRIGHT, 0L, OutputClass);
+			break;
+		case Qt::Key_Up:
+			if(is_shifted) dlg->Command(CMD_SHIFTUP, 0L, OutputClass);
+			else dlg->Command(CMD_CURRUP, 0L, OutputClass);
+			break;
+		case Qt::Key_Down:
+			if(is_shifted) dlg->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+			else dlg->Command(CMD_CURRDOWN, 0L, OutputClass);
+			break;
+		case Qt::Key_Delete:
+			dlg->Command(CMD_DELETE, 0L, OutputClass);
+			break;
+		case Qt::Key_Tab:
+			dlg->Command(CMD_TAB, 0L, OutputClass);
+			break;
+		case Qt::Key_Backtab:
+			dlg->Command(CMD_SHTAB, 0L, OutputClass);
+			break;
+		case Qt::Key_Home:
+			dlg->Command(CMD_POS_FIRST, 0L, OutputClass);
+			break;
+		case Qt::Key_End:
+			dlg->Command(CMD_POS_LAST, 0L, OutputClass);
+			break;
+		default:
+			QString kres = e->text();
+			for(i = 0; i < kres.length(); i++) {
+				qc = kres.at(i);	uc = qc.unicode();
+				if(uc == 3) dlg->Command(CMD_COPY, 0L, OutputClass);
+				else if(uc == 22) dlg->Command(CMD_PASTE, 0L, OutputClass);
+				else if(uc == 26) dlg->Command(CMD_UNDO, 0L, OutputClass);
+				else if(uc > 255) dlg->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass);
+				else dlg->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass);
+				}
+			break;
+		}
+	e->accept();
+}
+
+void
+DlgWidget::focusInEvent(QFocusEvent *e)
+{
+	if(Undo.cdisp)Undo.cdisp->MouseCursor(MC_ARROW, false);
+	raise();
+	CurrWidget = this;
+	if(x() || y()) {
+		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);
+#if QT_VERSION < 0x040000
+	w->setCaption(title);
+#else
+	w->setWindowTitle(title);
+#endif
+	if(flags & 0x2) w->setFixedSize(width, height);
+	else w->setFixedSize(width-6, height-16);
+	o = new OutputQT(w);	o->units = defs.cUnits;
+	o->Erase(0x00e0e0e0L);	if(flags & 0x04) w->startTimer(100);
+	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);
+		}
+	d->DoPlot(o);			w->show();
+	((DlgRoot*)d)->hDialog = w;
+#if QT_VERSION < 0x040000
+	w->setActiveWindow();
+#else
+	w->activateWindow();
+	QAppl->processEvents();		w->raise();
+#endif
+	return w;
+}
+
+void LoopDlgWnd() 	//keep message processing running
+{
+#if QT_VERSION < 0x040000
+	QAppl->processOneEvent();
+#else
+	QAppl->processEvents();
+#endif
+}
+
+void CloseDlgWnd(void *hDlg)
+{
+	HideCopyMark();
+	if(hDlg) {
+		delete((DlgWidget*) hDlg);
+		if(CurrWidgetPos.x > 50 && CurrWidgetPos.y > 50) {
+			CurrWidgetPos.x -= 50;		CurrWidgetPos.y -= 50;
+			}
+		}
+}
+
+void ShowDlgWnd(void *hDlg)
+{
+	if(hDlg){
+		((DlgWidget*)hDlg)->show();
+#if QT_VERSION >=0x040000
+		((DlgWidget*)hDlg)->activateWindow ();
+#else
+		((DlgWidget*)hDlg)->setActiveWindow();
+#endif
+		((DlgWidget*)hDlg)->raise();
+		((DlgWidget*)hDlg)->setFocus();
+		}
+}
+
+void ResizeDlgWnd(void *hDlg, int w, int h)
+{
+	((DlgWidget*)hDlg)->setFixedSize(w-6, h-16);
+	((DlgWidget*)hDlg)->show();
+	((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;
+}
+
diff --git a/QT_Spec.h b/QT_Spec.h
index ac260ae..0684c1c 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -1,342 +1,324 @@
-//QT_Spec.h, Copyright (c) 2001-2007 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 <qwidget.h>
-#include <qpen.h>
-#include <qpainter.h>
-#include <qprinter.h>
-#include <qmenubar.h>
-#include <qscrollbar.h>
-#include <qdragobject.h>
-#include "TheDialog.h"
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class TxtCurBlink:public QObject {
-	Q_OBJECT
-public:
-	anyOutput *oCopyMark;
-	anyOutput *bmCopyMark;
-
-	TxtCurBlink();
-	void Show();
-	void showCopyMark();
-
-protected:
-	void timerEvent(QTimerEvent *);
-
-private:
-	POINT line[5];
-	bool isVis;
-	int count, cp_mark;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//use sockets for to exchange clipboard data
-#ifdef RLP_PORT
-
-#include <qsocket.h>
-#include <qserversocket.h>
-
-class ReadCB:public QSocket {
-	Q_OBJECT
-public:
-	ReadCB(QObject *parent=0, const char *name=0, GraphObj *g=0);
-	~ReadCB();
-
-private slots:
-	void isConnected();
-	void receiveData();
-	void endData();
-	void isError(int);
-
-private:
-	int level;
-	char *format;
-	QObject *par;
-	GraphObj *DestGO;
-	QString *res;
-};
-
-class RLPsock:public QSocket {
-	Q_OBJECT
-public:
-	RLPsock(int sock, QObject *parent=0, const char *name=0, GraphObj *g=0);
-
-private slots:
-	void readClient();
-
-private:
-	QObject *par;
-	GraphObj *SourceGO;
-};
-
-class RLPserver:public QServerSocket {
-	Q_OBJECT
-public:
-	GraphObj *SourceGO;
-
-	RLPserver(QObject* parent=0, GraphObj *g=0);
-	~RLPserver();
-	void newConnection(int socket){new RLPsock(socket, this, 0, SourceGO);};
-
-	void SetGO(GraphObj *g);
-	char *GetXML();
-	char *GetRLP();
-	char *GetTXT() {return text_plain; };
-
-signals:
-	void newConnect(RLPsock *);
-
-private:
-	char *text_xml, *text_rlp, *text_plain;
-};
-
-#endif //RLP_PORT
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class RLPmenu:public QMenuBar {
-	Q_OBJECT
-public:
-	RLPmenu(QWidget *par, anyOutput *o, GraphObj *g);
-
-public slots:
-	void doMenuItem(int id);
-
-private:
-	anyOutput *OutputClass;
-	QWidget *parent;
-	GraphObj *BaseObj;
-
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The Qt widget class implementet for RLPlot
-class RLPwidget:public QWidget {
-	Q_OBJECT
-
-public:
-	QScrollBar *HScroll, *VScroll;
-	QPixmap *mempic;
-	RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0,
-		GraphObj *g = 0);
-	~RLPwidget();
-
-public slots:
-	void hScrollEvent(int pos);
-	void vScrollEvent(int pos);
-	void cmOpen();
-	void cmSaveData();
-	void cmSaveDataAs();
-	void cmExit();
-	void cmExitRLP();
-	void cmNewGraph();
-	void cmNewPage();
-	void cmDelGraph();
-	void cmAddPlot();
-	void cmAbout();
-	void cmAddRowCol();
-	void cmCopy();
-	void cmCut();
-	void cmPaste();
-	void cmCopyGraph();
-	void cmSaveGraphAs();
-	void cmRedraw();
-	void cmZoom25();
-	void cmZoom50();
-	void cmZoom100();
-	void cmZoom200();
-	void cmZoom400();
-	void cmZoomIn();
-	void cmZoomOut();
-	void cmZoomFit();
-	void cmPrint();
-	void cmExport();
-	void cmDelObj();
-	void cmUpdate();
-	void cmDefaults();
-	void cmAddAxis();
-	void cmAddLegend();
-	void cmLayers();
-	void cmUndo();
-	void cmFillRange();
-	void cmInsRow();
-	void cmInsCol();
-	void cmDelRow();
-	void cmDelCol();
-	void cmtStandard();
-	void cmtDraw();
-	void cmtPolyline();
-	void cmtPolygon();
-	void cmtRectangle();
-	void cmtRoundrect();
-	void cmtEllipse();
-	void cmtArrow();
-	void cmtText();
-	void cmSmplStat();
-	void cmRepCmeans();
-	void cmRepregr();
-	void cmReptwoway();
-	void cmFile1() {openHistoryFile(0);};
-	void cmFile2() {openHistoryFile(1);};
-	void cmFile3() {openHistoryFile(2);};
-	void cmFile4() {openHistoryFile(3);};
-	void cmFile5() {openHistoryFile(4);};
-	void cmFile6() {openHistoryFile(5);};
-
-protected:
-	void paintEvent(QPaintEvent *);
-	void resizeEvent(QResizeEvent *);
-	void closeEvent(QCloseEvent *);
-	void mouseDoubleClickEvent(QMouseEvent *e);
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void keyPressEvent(QKeyEvent *e);
-	void focusInEvent(QFocusEvent *e);
-
-private:
-	QWidget *parent;
-	anyOutput *OutputClass;
-	GraphObj *BaseObj;
-
-	void openHistoryFile(int idx);
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class DlgWidget:public QWidget {
-	Q_OBJECT
-public:
-	QPixmap *mempic;
-	anyOutput *OutputClass;
-
-	DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
-	~DlgWidget();
-
-protected:
-	void paintEvent(QPaintEvent *);
-	void mouseDoubleClickEvent(QMouseEvent *e);
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void keyPressEvent(QKeyEvent *e);
-	void focusInEvent(QFocusEvent *e);
-	void focusOutEvent(QFocusEvent *e);
-	void closeEvent(QCloseEvent *e);
-	void timerEvent(QTimerEvent *);
-
-private:
-	QWidget *parent;
-	tag_DlgObj *dlg;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class BitMapQT:public anyOutput {
-public:
-	QWidget *widget;
-	HatchOut *hgo;
-	QPixmap *mempic;
-	QImage *image;
-	QPen qPen;
-	QPainter qPainter;
-	QFont qFont;
-
-	BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98);
-	BitMapQT(int w, int h, double hr, double vr);
-	~BitMapQT();
-	bool SetLine(LineDEF *lDef);
-	bool SetFill(FillDEF *fill);
-	bool SetTextSpec(TextDEF *set);
-	virtual bool Erase(DWORD Color);
-	virtual bool StartPage() {return true;};
-	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
-		int sw, int sh, bool invert);
-	bool oGetTextExtent(char *text, int cb, int *width, int *height);
-	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
-	bool oGetPix(int x, int y, DWORD *col);
-	bool oDrawIcon(int type, int x, int y);
-	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
-	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSolidLine(POINT *p);
-	bool oTextOut(int x, int y, char *txt, int cb);
-	bool oTextOutW(int x, int y, w_char *txt, int cb);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class OutputQT:public BitMapQT {
-public:
-	QScrollBar *HScroll, *VScroll;
-
-	OutputQT(GraphObj *g);
-	OutputQT(DlgWidget *wi);
-	~OutputQT();
-	bool ActualSize(RECT *rc);
-	void Focus(){if(widget){widget->show(); widget->setActiveWindow();widget->raise();}};
-	void Caption(char *txt);
-	void MouseCursor(int cid, bool force);
-	bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
-	bool EndPage();
-	bool UpdateRect(RECT *rc, bool invert);
-	void ShowBitmap(int x, int y, anyOutput* src);
-	void ShowLine(POINT * pts, int cp, DWORD color);
-	void ShowEllipse(POINT p1, POINT p2, DWORD color); 
-	bool SetMenu(int type);
-	void CheckMenu(int mid, bool check);
-	void FileHistory();
-	void CreateNewWindow(GraphObj *g);
-
-private:
-	GraphObj *BaseObj;
-	RLPmenu *menu;
-};
-
-class PrintQT:public anyOutput{
-public:
-	HatchOut *hgo;
-	QPrinter *printer;
-
-	PrintQT(GraphObj *g, char *file);
-	~PrintQT();
-	bool ActualSize(RECT *rc);
-	bool SetLine(LineDEF *lDef);
-	bool SetFill(FillDEF *fill);
-	bool SetTextSpec(TextDEF *set);
-	bool StartPage();
-	bool EndPage();
-	bool Eject();
-	bool oGetTextExtent(char *text, int cb, int *width, int *height);
-	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
-	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
-	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
-	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
-	bool oSolidLine(POINT *p);
-	bool oTextOut(int x, int y, char *txt, int cb);
-	bool oTextOutW(int x, int y, w_char *txt, int cb);
-	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-
-private:
-	QPen qPen;
-	QFont qFont;
-	QPainter qPainter;
-	QWMatrix dxf;
-	char *fileName;
-	GraphObj *go;
-	bool bPrinting;
-};
+//QT_Spec.h, Copyright (c) 2001-2007 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 "menu.h"
+#include "TheDialog.h"
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qnamespace.h>
+
+#if QT_VERSION < 0x040000
+	#include <qpen.h>
+	#include <qprinter.h>
+	#include <qdragobject.h>
+	#include <qmenubar.h>
+	#include <qscrollbar.h>
+	#include <qmessagebox.h>
+	#include <qpixmap.h>
+	#include <qfiledialog.h>
+	#include <qimage.h>
+	#include <qcursor.h>
+	#include <qclipboard.h>
+	#include <qbuffer.h>
+	#include <qbitmap.h>
+	#include <qtextstream.h>
+#else 
+	#include <QtGui>
+#endif
+
+#define RLP_PORT	4321		//enable clipboard server
+#ifdef RLP_PORT
+	#include <sys/socket.h>
+	#include <netdb.h>
+	#include <pthread.h>
+	#include <fcntl.h>
+	#include <unistd.h>
+	#include <sys/ioctl.h>
+	#include <linux/fs.h> 
+#endif
+
+bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj);
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class TxtCurBlink:public QObject {
+	Q_OBJECT
+public:
+	TxtCurBlink();
+	void Show();
+//	void showCopyMark();
+
+protected:
+	void timerEvent(QTimerEvent *);
+
+private:
+	bool isVis;
+	int count;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use sockets for to exchange clipboard data
+// undefine RLP_PORT to limit clipboard to a single instance
+
+class RLPserver {
+public:
+	GraphObj *SourceGO;
+
+	RLPserver(QObject* parent=0, GraphObj *g=0);
+	~RLPserver();
+
+	void SetGO(GraphObj *g);
+	char *GetXML();
+	char *GetRLP();
+	char *GetTXT() {return text_plain; };
+	bool ok() {return true;};
+#ifdef RLP_PORT
+	int Socket() {return sock;};
+#endif
+
+private:
+	char *text_xml, *text_rlp, *text_plain;
+#ifdef RLP_PORT
+	pthread_t thread;
+	pthread_attr_t thread_attr;
+	int sock;
+#endif
+};
+
+#if QT_VERSION < 0x040000 
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class RLPmenu:public QMenuBar {
+	Q_OBJECT
+public:
+	RLPmenu(QWidget *par, anyOutput *o, GraphObj *g);
+
+public slots:
+	void doMenuItem(int id);
+
+private:
+	anyOutput *OutputClass;
+	QWidget *parent;
+	GraphObj *BaseObj;
+
+};
+
+#else 			//Qt version >= 4.0
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class RLPaction:public QAction {
+	Q_OBJECT
+public:
+	RLPaction(QWidget *par, anyOutput *o, GraphObj *g, char *name, int id);
+	~RLPaction(){;};
+
+public slots:
+	void doMenuItem();
+
+private:
+	int Id;
+	anyOutput *OutputClass;
+	QWidget *parent;
+	GraphObj *BaseObj;
+};
+
+#endif
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The Qt widget class implementet for RLPlot
+class RLPwidget:public QMainWindow {
+	Q_OBJECT
+
+public:
+	QScrollBar *HScroll, *VScroll;
+	QPixmap *mempic;
+	QMenuBar *menu_bar;
+
+	RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0,
+		GraphObj *g = 0);
+	~RLPwidget();
+	void openHistoryFile(int idx);
+
+public slots:
+	void hScrollEvent(int pos);
+	void vScrollEvent(int pos);
+	void cmNOP(){;};
+	void cmCopy(){ProcMenuEvent(CM_COPY, this, OutputClass, BaseObj);};
+	void cmCut(){ProcMenuEvent(CM_CUT, this, OutputClass, BaseObj);};
+	void cmZoomIn(){ProcMenuEvent(CM_ZOOMIN, this, OutputClass, BaseObj);};
+	void cmZoomOut(){ProcMenuEvent(CM_ZOOMOUT, this, OutputClass, BaseObj);};
+	void cmZoomFit(){ProcMenuEvent(CM_ZOOMFIT, this, OutputClass, BaseObj);};
+	void cmPaste();
+	void cmUndo(){if(BaseObj) BaseObj->Command(CMD_UNDO, 0L, OutputClass);};
+
+protected:
+	void paintEvent(QPaintEvent *);
+	void resizeEvent(QResizeEvent *);
+	void closeEvent(QCloseEvent *);
+	void mouseDoubleClickEvent(QMouseEvent *e);
+	void mousePressEvent(QMouseEvent *e);
+	void mouseReleaseEvent(QMouseEvent *e);
+	void mouseMoveEvent(QMouseEvent *e);
+	void keyPressEvent(QKeyEvent *e);
+	void focusInEvent(QFocusEvent *e);
+
+private:
+	QWidget *parent;
+	anyOutput *OutputClass;
+	GraphObj *BaseObj;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#if QT_VERSION < 0x040000
+class DlgWidget:public QWidget {
+#else
+class DlgWidget:public QWidget {
+#endif
+	Q_OBJECT
+public:
+	QPixmap *mempic;
+	anyOutput *OutputClass;
+
+	DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
+	~DlgWidget();
+
+protected:
+	void paintEvent(QPaintEvent *);
+	void mouseDoubleClickEvent(QMouseEvent *e);
+	void mousePressEvent(QMouseEvent *e);
+	void mouseReleaseEvent(QMouseEvent *e);
+	void mouseMoveEvent(QMouseEvent *e);
+	void keyPressEvent(QKeyEvent *e);
+	void focusInEvent(QFocusEvent *e);
+	void focusOutEvent(QFocusEvent *e);
+	void closeEvent(QCloseEvent *e);
+	void timerEvent(QTimerEvent *);
+
+private:
+	QWidget *parent;
+	tag_DlgObj *dlg;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class BitMapQT:public anyOutput {
+public:
+	QMainWindow *widget;
+	QWidget *dlgwidget;
+	HatchOut *hgo;
+	QPixmap *mempic;
+	QImage *image;
+	QPen qPen;
+	QPainter qPainter;
+	QFont qFont;
+	void *ShowObj;				//eph_obj
+	void *ShowAnimated;			//copy mark
+
+	BitMapQT(GraphObj *g, QMainWindow *wi, int vr = 98, int hr = 98);
+	BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98);
+	BitMapQT(int w, int h, double hr, double vr);
+	~BitMapQT();
+	bool SetLine(LineDEF *lDef);
+	bool SetFill(FillDEF *fill);
+	bool SetTextSpec(TextDEF *set);
+	virtual bool Erase(DWORD Color);
+	virtual bool StartPage() {return true;};
+	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+		int sw, int sh, bool invert);
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
+	bool oGetPix(int x, int y, DWORD *col);
+	bool oDrawIcon(int type, int x, int y);
+	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oSolidLine(POINT *p);
+	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
+	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class OutputQT:public BitMapQT {
+public:
+	QScrollBar *HScroll, *VScroll;
+#if QT_VERSION < 0x040000
+	RLPmenu *menu;
+#else
+	QAction *itFil1, *itFil2, *itFil3, *itFil4, *itFil5, *itFil6;
+	QAction *ittStd, *ittDraw, *ittPl, *ittPg, *ittRec, *ittRrec, *ittElly, *ittArr, *ittTxt;
+#endif
+
+	OutputQT(GraphObj *g);
+	OutputQT(DlgWidget *wi);
+	~OutputQT();
+	bool ActualSize(RECT *rc);
+	void Focus(){if(widget){widget->show(); widget->activateWindow();widget->raise();}};
+	void Caption(char *txt);
+	void MouseCursor(int cid, bool force);
+	bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
+	bool EndPage();
+	bool UpdateRect(RECT *rc, bool invert);
+	void ShowLine(POINT * pts, int cp, DWORD color);
+	void ShowEllipse(POINT p1, POINT p2, DWORD color); 
+	bool SetMenu(int type);
+	void CheckMenu(int mid, bool check);
+	void FileHistory();
+	void CreateNewWindow(GraphObj *g);
+
+private:
+	GraphObj *BaseObj;
+};
+
+class PrintQT:public anyOutput{
+public:
+	HatchOut *hgo;
+	QPrinter *printer;
+
+	PrintQT(GraphObj *g, char *file);
+	~PrintQT();
+	bool ActualSize(RECT *rc);
+	bool SetLine(LineDEF *lDef);
+	bool SetFill(FillDEF *fill);
+	bool SetTextSpec(TextDEF *set);
+	bool StartPage();
+	bool EndPage();
+	bool Eject();
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
+	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+	bool oSolidLine(POINT *p);
+	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
+	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+	QPen qPen;
+	QFont qFont;
+	QPainter qPainter;
+#if QT_VERSION >= 0x040000
+	QMatrix dxf;
+#else
+	QWMatrix dxf;
+#endif
+	char *fileName;
+	GraphObj *go;
+	bool bPrinting;
+};
+
diff --git a/README b/README
index 791b432..58520b9 100755
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-README for RLPlot, Copyright (c) 2002, 2003 R.Lackner
+README for RLPlot, Copyright (c) 2002-2007 R.Lackner
 
     This file is part of RLPlot.
 
@@ -18,114 +18,21 @@ README for RLPlot, Copyright (c) 2002, 2003 R.Lackner
 
 
 ------------------------------------------------------------------------------
-1. Building RLPlot for Linux
-Before building RLPlot for Linux using the supplied 'Makefile' you probably
-need to make some adaptations. RLPlot uses Trolltech's Qt and the default
-Makefile assumes Qt beeing installed in /usr/local/qt.
-Which version of Qt should be used ? The best version is usually that coming
-with your distribution CDs. If there are several versions installed on your
-machine you may experience crashes especially if you try to copy/paste data
-from one application to another.
-Most problems during compilation of RLPlot are due to missing Qt or installation
-of Qt in a different folder. 
-On most systems where Qt has been installed from the distribution
-CDs the environment variable 'QTDIR' is defined. In this case you may succeed
-by issuing the following command within the RLPlot folder:
+The current version of RLPlot (Version 1.4) can be compiled using Qt3, Qt4 or
+Windows. For compilation with Qt see the supplied Makefile declarations section.
+Further information also concerning the build for Windows can be obtained form
+the online documentation: http://rlplot.sourceforge.net/Docs/index.html
+RLPlot for Windows is a native Windows application which is also compatible
+with Wine.
 
-      make -e
-
-If that does not work you have to ...
-
-1.1: Find your Qt directory.
-   This is the directory where Qt has been installed. It contains the files
-   ./bin/moc, ./include/qapplication.h ./lib/libqt.so (However, RLPlot needs
-   more than those). If you don't find this directory you must install Qt devel.
-   first from your distribution CDs or directly from www.trolltech.com.
-
-1.2: Modify Makefile. Find the line (close to the top) where QTDIR is defined
-   and fill in the path to the Qt folder.
-   Possible examples include:
-      QTDIR = /usr/lib/qt3
-      QTDIR = /usr/lib/qt-2.3.1
-	  QTDIR = /usr/local/qt-2.3.1
-	  QTDIR = /usr/local/qt-x11-free-3.0.4
-
-	Alternatively you may leave the Makefile unchanged and put a symbolic link
-	into /usr/local (if /usr/local/qt does not yet exist), for example:
-		cd /usr/local
-		ln -s /usr/lib/qt-2.3.1 qt
-	The latter method has the advantage that you can have concurrent versions
-	of Qt installed on your system and need not modify Makefile everytime you
-	download a new version of RLPlot. You may need root privileges to create
-	the link in /usr/local
-
-1.3: Create the RLPlot executable by execting 'make' in the RLplot folder.
-   You can remove some intermediary file exceting 'make clean'.
-   No further installation required. Just execute RLPlot.	   
-
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-Problems and Platform notes:
-Some recent versions of Qt use Open GL which requires additional libraries
-to be included in the Makefile.
-
-Common errors during build:
-
-undefined reference to ...
-   This error usually occurs if a library necessary for link is not specified
-   in the Makefile. You have to find a suitable library and specify it in the
-   LIBS definition (some examples see below). May be you do not need this library
-   and the build is done properly without e.g. '-lGL'.
-   Example: undefined reference to 'glXQueryServerString'
-      libGL.so not specified in LIBS. Add '-lGL' to LIBS or a fully qualified
-	  path to the folder with libGL.so, e.g. -L/usr/X11R6/lib 
-
-cannot find ....
-   This error occurs if a file is not found, possibly one of the libraries in
-   of the LIBS definition. Probably you do not need this library and you can
-   remove it from the LIBS. If this does not help you may be lucky to find it
-   elsewhere (not very promising) or some package needs to be installed.
-   Example: cannot find -lGL
-      libGL.so specified in LIBS but not found in a standard directory
-   Example: cannot find -lqt-mt
-      libqt-mt.so not found. Modify the Makefile from 'QTLIBS= -lqt-mt' to
-      'QTLIBS= -lqt'. If this does not help Qt is not properly installed.
-
-There are some LIBS definitions which might work on your system
-   LIBS = -L$(QTDIR)/lib -L/usr/X11R6/lib
-   LIBS = -lGL -L$(QTDIR)/lib -L/usr/X11R6/lib
-   LIBS = -L/usr/lib -L$(QTDIR)/lib -L/usr/X11R6/lib
-
-------------------------------------------------------------------------------
-2. Building RLPlot for Windows
-To compile RLPlot from the sources you need to install
-MS Visual Studio first. Once you have RLPlot.exe no further installation
-is required. RLPlot does not change the registry. Double click on
-the icon in the explorer window to start the program.
-
-2.1 Building RLPlot.exe using NMAKE
-   Open a DOS or command line window and move to the MSVC folder. Execute
-   VCVARS32.BAT in the bin subdirectory. Change directory to the RLPlot
-   folder. Whenever you close the DOS-box you need to execute VCVARS32.BAT
-   again. Now execute nmake to compile and build RLPlot:
-        nmake -f "Makefile.win"
-   After building RLPlot you may wish to remove temporary files:
-        nmake -f "Makefile.win" clean
-
-2.2 Creating a project in the IDE
-   Create a new project (RLPLot) using the MS Developer Studio creating a
-   Win32 Application. Add the following files to the project: Export.cpp,
-   FileIO.cpp, Output.cpp, PropertyDlg.cpp, rlplot.cpp, rlplot.h, RLPLOT.RC,
-   spreadwi.cpp, TheDialog.cpp, TheDialog.h, UtilObj.cpp, Utils.cpp,
-   Version.h, WinSpec.cpp, WinSpec.h. Now execute [!].
-
-------------------------------------------------------------------------------
 
 Success!
 
 reinhard.lackner at uibk.ac.at
 
 Reinhard Lackner                               Reinhard Lackner
-Ing. Etzelstr. 19                              Inst. f. Zoologie u. Limnologie
+Ing. Etzelstr. 19                              Inst. f. Zoologie
 A-6020 Innsbruck                               Technikerstr. 25
 AUSTRIA                                        A-6020 Innsbruck
                                                AUSTRIA
+
diff --git a/RLPLOT.ICO b/RLPLOT.ICO
old mode 100644
new mode 100755
diff --git a/RLPlot.bmp b/RLPlot.bmp
old mode 100644
new mode 100755
diff --git a/RLPlot.xpm b/RLPlot.xpm
old mode 100644
new mode 100755
diff --git a/TheDialog.cpp b/TheDialog.cpp
index 341e24c..8350595 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -65,10 +65,11 @@ DlgRoot::DlgRoot(DlgInfo *tmpl, DataObj *d)
 	DlgText.iSize = dlgtxtheight;		DlgText.ColBg = DlgBGcolor;
 	DlgText.fSize = defs.GetSize(SIZE_TEXT);
 	type = NONE;		Id = -2;		cContinue = 0;
-	bActive = bRedraw = false;			Result = -1;	c_go = CurrGO;
+	bActive = bRedraw = false;			c_go = CurrGO;
 	CurrDisp = 0L;		oldFocus = DialogFocus;		DialogFocus = 0L;
 	oldDefault = DialogDefault;			oldTabStop = DialogTabStop;
-	data = d;			ParentOut = Undo.cdisp;
+	data = d;			res_put = res_get = 0;		hDialog = 0L;
+	if(ParentOut = Undo.cdisp) ParentOut->MouseCursor(MC_WAIT, false);
 	mrk_item = 0L;		//if an item has a mark its this one
 	if(tmpl) {
 		//count number of items first, then allocate memory
@@ -251,6 +252,7 @@ DlgRoot::~DlgRoot()
 	if(tabstops) free(tabstops);	tabstops = 0L;
 	DialogFocus = oldFocus;			DialogDefault = oldDefault;
 	DialogTabStop = oldTabStop;		CurrGO = c_go;
+	if(Undo.cdisp)Undo.cdisp->MouseCursor(MC_ARROW, false);
 }
 
 bool
@@ -296,16 +298,18 @@ DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_ENDDIALOG:
 		d = (Dialog *)tmpl;
 		if(d) {
-			Result = d->Id;		// end dialog by object
+			res_q[res_put++] = d->Id;		// end dialog by object
 			cContinue = 0;
 			}
-		else if(cContinue >0) {
+		else if(cContinue >0) {				// no end upon killing the focus
 			cContinue--;
-			return true;		// no end upon killing the focus
+			return true;
 			}
 		else {
-			Result = 0;			// end dialog with closebox or loose focus
+			res_q[res_put++] = 0;			// end dialog with closebox or loose focus
+			bRedraw = true;
 			}
+		res_put &= 0xff;
 		return true;
 	case CMD_CONTINUE:
 		cContinue++;
@@ -415,6 +419,7 @@ DlgRoot::DoPlot(anyOutput *o)
 	int i;
 
 	HideCopyMark();			mrk_item = 0L;			bRedraw = false;
+	HideTextCursor();
 	if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
 	if(o)CurrDisp = o;		DialogDefault = 0L;
 	if(CurrDisp) {
@@ -616,9 +621,10 @@ DlgRoot::GetResult()
 {
 	int ret;
 
-	ret = Result;				Result = -1;
+	if(res_put != res_get) ret = res_q[res_get++];
+	else ret = -1;
+	res_get &= 0xff;
 	if(bRedraw)DoPlot(0L);
-	//return each result only once !
 	if(ret >= 0 && ParentOut) Undo.SetDisp(ParentOut);
 	return ret;
 }
@@ -699,11 +705,13 @@ DlgRoot::Activate(int id, bool active)
 bool
 DlgRoot::ItemCmd(int id, int cmd, void *tmpl)
 {
-	 int i;
+	int i;
 
-	 if((i = FindIndex(id)) && dlg[i]) 
-		 return dlg[i]->dialog->Command(cmd, tmpl, CurrDisp);
-	 return false;
+	if((i = FindIndex(id)) && dlg[i]){ 
+		bRedraw = true;
+		return dlg[i]->dialog->Command(cmd, tmpl, CurrDisp);
+		}
+	return false;
 }
 
 Dialog::Dialog(tag_DlgObj *par, DlgInfo *desc, RECT rec)
@@ -711,16 +719,11 @@ Dialog::Dialog(tag_DlgObj *par, DlgInfo *desc, RECT rec)
 	parent = par;
 	Id = desc->id;
 	flags = desc->flags;
-	memcpy(&cr, &rec, sizeof(RECT));
-	memcpy(&hcr, &rec, sizeof(RECT));
-	Line.width = 0.0;
-	Line.patlength = 1.0;
-	Line.color = DlgBGcolor;
-	Line.pattern = 0x00000000L;
-	Fill.type = FILL_NONE;
-	Fill.color = DlgBGcolor;
-	Fill.scale = 1.0;
-	Fill.hatch = 0L;
+	memcpy(&cr, &rec, sizeof(RECT));	memcpy(&hcr, &rec, sizeof(RECT));
+	Line.width = 0.0;					Line.patlength = 1.0;
+	Line.color = DlgBGcolor;			Line.pattern = 0x00000000L;
+	Fill.type = FILL_NONE;				Fill.color = DlgBGcolor;
+	Fill.scale = 1.0;					Fill.hatch = 0L;
 	memcpy(&TextDef, &DlgText, sizeof(TextDEF));
 	type = desc->type;
 	bChecked = flags & CHECKED ? true : false;
@@ -975,8 +978,7 @@ ArrowButton::DoPlot(anyOutput *o)
 	Fill.color = DlgBGhigh;
 	ix = (dx =(cr.right-cr.left))>5 ? dx>>2 : 2;
 	iy = (dy =(cr.bottom-cr.top))>5 ? dy>>2 : 2;
-	o->SetLine(&Line);
-	o->SetFill(&Fill);
+	o->SetLine(&Line);						o->SetFill(&Fill);
 	if(bLBdown) o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
 	else {
 		o->oRectangle(cr.left, cr.top, cr.right-1, cr.bottom-1);
@@ -984,50 +986,35 @@ ArrowButton::DoPlot(anyOutput *o)
 		o->SetLine(&Line);
 		pts[0].x = cr.left;					pts[0].y = pts[1].y = cr.bottom-1;
 		pts[1].x = pts[2].x = cr.right-1;	pts[2].y = cr.top-1;
-		o->oPolyline(pts, 3);
-		Line.color = 0x00ffffffL;
-		o->SetLine(&Line);
-		pts[0].x = pts[1].x = cr.left;
-		pts[0].y = cr.bottom -3;
-		pts[1].y = pts[2].y = cr.top;
-		pts[2].x = cr.right -2;
-		o->oPolyline(pts, 3);
+		o->oPolyline(pts, 3);				Line.color = 0x00ffffffL;
+		o->SetLine(&Line);					pts[0].x = pts[1].x = cr.left;
+		pts[0].y = cr.bottom -3;			pts[1].y = pts[2].y = cr.top;
+		pts[2].x = cr.right -2;				o->oPolyline(pts, 3);
 		}
 	Fill.color = Line.color = 0x00000000L;
-	o->SetLine(&Line);
-	o->SetFill(&Fill);
+	o->SetLine(&Line);						o->SetFill(&Fill);
 	switch(direct) {
 	case 1:
-		pts[0].x = pts[3].x = cr.left+ix;
-		pts[0].y = pts[3].y = pts[1].y = cr.bottom-(iy<<1);
-		pts[1].x = cr.right-(ix<<1);
-		pts[2].x = (cr.right + cr.left)/2 -1;
-		pts[2].y = cr.top+iy;
-		o->oPolygon(pts, 4);
+		pts[0].x = pts[3].x = cr.left+ix;	pts[0].y = pts[3].y = pts[1].y = cr.bottom-(iy<<1);
+		pts[1].x = cr.right-(ix<<1);		pts[2].x = (cr.right + cr.left)/2 -1;
+		pts[2].y = cr.top+iy;				o->oPolygon(pts, 4);
 		break;
 	case 2:
-		pts[0].x = pts[3].x = cr.left+ix;
-		pts[0].y = pts[3].y = pts[1].y = cr.top+iy;
-		pts[1].x = cr.right-(ix<<1);
-		pts[2].x = (cr.right + cr.left)/2 -1;
-		pts[2].y = cr.bottom-(iy<<1);
-		o->oPolygon(pts, 4);
+		pts[0].x = pts[3].x = cr.left+ix;	pts[0].y = pts[3].y = pts[1].y = cr.top+iy;
+		pts[1].x = cr.right-(ix<<1);		pts[2].x = (cr.right + cr.left)/2 -1;
+		pts[2].y = cr.bottom-(iy<<1);		o->oPolygon(pts, 4);
 		break;
 	case 3:
-		pts[0].x = pts[3].x = cr.left+ix;
-		pts[0].y = pts[3].y = (cr.bottom + cr.top)/2-1;
+		pts[0].x = pts[3].x = cr.left+ix;	pts[0].y = pts[3].y = (cr.bottom + cr.top)/2-1;
 		pts[1].x = pts[2].x = cr.right-(ix<<1);
-		pts[1].y = cr.bottom-(iy<<1);
-		pts[2].y = cr.top+iy;
+		pts[1].y = cr.bottom-(iy<<1);		pts[2].y = cr.top+iy;
 		o->oPolygon(pts, 4);
 		break;
 	case 4:
 		pts[0].x = pts[3].x = cr.right-(ix<<1);
 		pts[0].y = pts[3].y = (cr.bottom + cr.top)/2-1;
-		pts[1].x = pts[2].x = cr.left+2;
-		pts[1].y = cr.bottom-(iy<<1);
-		pts[2].y = cr.top+iy;
-		o->oPolygon(pts, 4);
+		pts[1].x = pts[2].x = cr.left+2;	pts[1].y = cr.bottom-(iy<<1);
+		pts[2].y = cr.top+iy;				o->oPolygon(pts, 4);
 		break;
 		}
 	o->UpdateRect(&cr, false);
@@ -1037,14 +1024,12 @@ bool
 ArrowButton::Select(int x, int y, anyOutput *o)
 {
 	if(IsInRect(&cr, x, y)) {
-		bLBdown = false;
-		DoPlot(o);
+		bLBdown = false;					DoPlot(o);
 		if(parent) parent->Command(CMD_ENDDIALOG, (void *)this, o);
 		return true;
 		}
 	else if(bLBdown) {
-		bLBdown = false;
-		DoPlot(o);
+		bLBdown = false;					DoPlot(o);
 		}
 	return false;
 }
@@ -1256,8 +1241,12 @@ SymButton::DoPlot(anyOutput *o)
 bool
 SymButton::Select(int x, int y, anyOutput *o)
 {
-	if(IsInRect(&cr, x, y)) {
-		if((flags & TOUCHEXIT) && parent) 
+	if(parent && IsInRect(&cr, x, y)) {
+		if((flags & OWNDIALOG) && (*(symbol))) {
+			parent->Command(CMD_CONTINUE, 0L, o);
+			(*symbol)->PropertyDlg();
+			}
+		if((flags & TOUCHEXIT)) 
 			parent->Command(CMD_ENDDIALOG, (void *)this, o);
 		DoPlot(o);
 		return true;
@@ -3277,27 +3266,44 @@ int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev.",
 	"%", "color", "x-value", "y-value", "z-value", TmpTxt, TmpTxt+100, TmpTxt+200,
-	TmpTxt+300, TmpTxt+400};
+	TmpTxt+300, TmpTxt+400, "left", "right", "top", "bottom", "x-axis", "y-axis", "z-axis"};
 
 DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 {
 	char **lines, **fields, **flags, error[80];
-	int i, j, nlines, nfields, nflags;
+	int i, j, nlines, nfields, nflags, last_id, last_next;
 	unsigned int hv;
 	DlgInfo *Dlg;
 
 	std_text[2] = Units[defs.cUnits].display;
 	lines = split(tmpl, '\n', &nlines);
 	if(!lines || nlines <1 ||(!(Dlg = (DlgInfo*)malloc(nlines*sizeof(DlgInfo))))) return 0L;
-	for(i = 0; i < nlines; i++) if(lines[i] && lines[i][0]){
+	for(i = last_id = last_next = 0; i < nlines; i++) if(lines[i] && lines[i][0]){
 		if(fields = split(lines[i], ',', &nfields)) {
 			if(nfields == 10) {
 				Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+				if(fields[0][0]) {
+					if(fields[0][0] == '.') Dlg[i].id = (last_id += 1);
+					else 
+#ifdef USE_WIN_SECURE
+						sscanf_s(fields[0], "%d", &Dlg[i].id);		last_id = Dlg[i].id;
+#else
+						sscanf(fields[0], "%d", &Dlg[i].id);		last_id = Dlg[i].id;
+#endif
+					}
+				if(fields[1][0]) {
+					if(fields[1][0] == '+') Dlg[i].next = (last_id + 1);
+					else if(fields[1][0] == '.') Dlg[i].next = (last_next += 1);
+					else 
+#ifdef USE_WIN_SECURE
+						sscanf_s(fields[1], "%d", &Dlg[i].next);	last_next = Dlg[i].next;
+#else
+						sscanf(fields[1], "%d", &Dlg[i].next);		last_next = Dlg[i].next;
+#endif
+					}
 #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);
 #endif
 				Dlg[i].flags = 0L;
@@ -4019,35 +4025,38 @@ void RLPlotInfo()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // change spreadsheet settings
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char * SSDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,122,10,40,12\n"
+	"2,3,,,PUSHBUTTON,-2,122,25,40,12\n"
+	"3,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"5,6,100,ISPARENT | CHECKED,SHEET,1,5,10,108,80\n"
+	"6,,200,ISPARENT,SHEET,2,5,10,108, 80\n"
+	"100,101,,,LTEXT,3,15,25,60,8\n"
+	"101,102,,,EDTEXT,-16,40,37,40,10\n"
+	"102,103,,,LTEXT,4,15,52,60,8\n"
+	"103,,,,EDTEXT,-17,40,64,40,10\n"
+	"200,201,,,RTEXT,5,10,29,40,8\n"
+	"201,202,,,EDVAL1,6,52,29,25,10\n"
+	"202,203,,,LTEXT,7,79,29,20,8\n"
+	"203,204,,,RTEXT,8,10,44,40,8\n"
+	"204,205,,,EDVAL1,9,52,44,25,10\n"
+	"205,206,,,LTEXT,7,79,44,20,8\n"
+	"206,207,,,RTEXT,10,10,59,40,8\n"
+	"207,208,,,EDVAL1,11,52,59,25,10\n"
+	"208,209,,,LTEXT,-3,79,59,20,8\n"
+	"209,210,,,RTEXT,12,10,74,40,8\n"
+	"210,211,,,INCDECVAL1,13,52,74,33,10\n"
+	"211,,,LASTOBJ,LTEXT,-10,87,74,20,8";
 bool
-DoSpShSize(DataObj *dt)
+DoSpShSize(DataObj *dt, GraphObj *parent)
 {
 	TabSHEET tab1 = {0, 45, 10, "Dimensions"};
-	TabSHEET tab2 = {45, 105, 10, "Width and Height"};
-	char txt1[40], txt2[40];
+	TabSHEET tab2 = {45, 108, 10, "Width and Height"};
 	double fw, cw, ch, th;
-	DlgInfo SSDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 115, 10, 40, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 115, 25, 40, 12},
-		{3, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 105, 80},
-		{6, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 105, 80},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"number of columns:", 15, 25, 60, 8},
-		{101, 102, 0, 0x0L, EDTEXT, txt1, 40, 37, 40, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void*)"number of rows:", 15, 52, 60, 8},
-		{103, 0, 0, 0x0L, EDTEXT, txt2, 40, 64, 40, 10},
-		{200, 201, 0, 0x0L, RTEXT, (void*)"row buttons", 10, 29, 40, 8},
-		{201, 202, 0, 0x0L, EDVAL1, &fw, 52, 29, 25, 10},
-		{202, 203, 0, 0x0L, LTEXT, (void*)"[digits]", 79, 29, 20, 8},
-		{203, 204, 0, 0x0L, RTEXT, (void*)"column width", 10, 44, 40, 8},
-		{204, 205, 0, 0x0L, EDVAL1, &cw, 52, 44, 25, 10},
-		{205, 206, 0, 0x0L, LTEXT, (void*)"[digits]", 79, 44, 20, 8},
-		{206, 207, 0, 0x0L, RTEXT, (void*)"row height", 10, 59, 40, 8},
-		{207, 208, 0, 0x0L, EDVAL1, &ch, 52, 59, 25, 10},
-		{208, 209, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 79, 59, 20, 8},
-		{209, 210, 0, 0x0L, RTEXT, (void*)"text size", 10, 74, 40, 8},
-		{210, 211, 0, 0x0L, INCDECVAL1, &th, 52, 74, 33, 10},
-		{211, 0, 0, LASTOBJ, LTEXT, (void *)"%", 87, 74, 20, 8}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"number of columns:", (void*)"number of rows:",
+		(void*)"row buttons", (void*)&fw, (void*)"[digits]", (void*)"column width", (void*)&cw,
+		(void*)"row height", (void*)&ch, (void*)"text size", (void*)&th};
+	DlgInfo *SSDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int w1, w2, h1, h2, res, celldim[3], ith;
@@ -4055,6 +4064,7 @@ DoSpShSize(DataObj *dt)
 	double fw1, cw1, ch1, th1;
 
 	if(!dt || !dt->GetSize(&w1, &h1)) return false;
+	if(!(SSDlg = CompileDialog(SSDlg_Tmpl, dyndata))) return false;
 	dt->Command(CMD_GET_CELLDIMS, &celldim, 0L);
 	fw1 = fw = NiceValue(((double)celldim[0])/((double)(celldim[2]-2)/2.0));
 	cw1 = cw = NiceValue(((double)celldim[1])/((double)(celldim[2]-2)/2.0));
@@ -4065,20 +4075,20 @@ DoSpShSize(DataObj *dt)
 		}
 	ch1 = ch;						th = th1 = defs.ss_txt*100.0;
 #ifdef USE_WIN_SECURE
-	sprintf_s(txt1, 40, "%d", w1);		sprintf_s(txt2, 40, "%d", h1);
+	sprintf_s(TmpTxt+100, 40, "%d", w1);		sprintf_s(TmpTxt+200, 40, "%d", h1);
 #else
-	sprintf(txt1, "%d", w1);			sprintf(txt2, "%d", h1);
+	sprintf(TmpTxt+100, "%d", w1);			sprintf(TmpTxt+200, "%d", h1);
 #endif
 	Dlg = new DlgRoot(SSDlg, dt);
-	hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 320, 220, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 340, 220, Dlg, 0x0L);
 	Dlg->GetValue(201, &fw1);	Dlg->GetValue(204, &cw1);	Dlg->GetValue(207, &ch1);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch(res) {
 		case 1:					//OK pressed
-			if(Dlg->GetText(101, txt1, 40) && Dlg->GetText(103, txt2, 40)) {
-				w2 = atol(txt1);		h2 = atol(txt2);
+			if(Dlg->GetText(101, TmpTxt+100, 40) && Dlg->GetText(103, TmpTxt+200, 40)) {
+				w2 = atol(TmpTxt+100);		h2 = atol(TmpTxt+200);
 				w2 = w2 > 0 ? w2: w1;	h2 = h2 > 0 ? h2: h1;
 				}
 			else res = -1;
@@ -4087,6 +4097,7 @@ DoSpShSize(DataObj *dt)
 		}while(res <0);
 	if(res == 1){
 		if(Dlg->GetValue(207, &ch) && Dlg->GetValue(210, &th) && ch > 0.001) {
+			Undo.ValFloat(parent, &defs.ss_txt, 0L);
 			defs.ss_txt = th = th >= 10.0 && th <= 100 ? th/100.0 : 1.0; 
 			switch(defs.cUnits) {
 			case 1:		
@@ -4112,8 +4123,7 @@ DoSpShSize(DataObj *dt)
 			ErrorBox("Failed to set new dimensions\nof Spreadsheet.");
 		else bRet = true;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(SSDlg);
 	return bRet;
 }
 
@@ -4233,28 +4243,33 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Get resolution and size for exported bitmap
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char * ResDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,125,10,35,12\n"
+	"2,100,,,PUSHBUTTON,-2,125,25,35,12\n"
+	"100,+,,,LTEXT,1,20,10,50,9\n"
+	".,.,,,RTEXT,2,20,22,35,9\n"
+	".,.,,,EDVAL1,3,57,22,30,10\n"
+	".,.,,,LTEXT,-3,89,22,20,8\n"
+	".,.,,,RTEXT,4,20,34,35,9\n"
+	".,.,,,EDVAL1,5,57,34,30,10\n"
+	".,.,,,LTEXT,-3,89,34,20,8\n"
+	".,.,,,RTEXT,6,20,46,35,9\n"
+	".,.,,,EDVAL1,7,57,46,30,10\n"
+	".,,,LASTOBJ,LTEXT,8,89,46,20,8";
+
 bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
 {
-	DlgInfo ResDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 105, 10, 35, 12},
-		{2, 100, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 105, 25, 35, 12},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"Image properties:", 10, 10, 50, 9},
-		{101, 102, 0, 0x0L, RTEXT, (void*)"width", 10, 22, 35, 9},
-		{102, 103, 0, 0x0L, EDVAL1, width, 47, 22, 30, 10},
-		{103, 104, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 79, 22, 20, 8},
-		{104, 105, 0, 0x0L, RTEXT, (void*)"height", 10, 34, 35, 9},
-		{105, 106, 0, 0x0L, EDVAL1, height, 47, 34, 30, 10},
-		{106, 107, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 79, 34, 20, 8},
-		{107, 108, 0, 0x0L, RTEXT, (void*)"resolution", 10, 46, 35, 9},
-		{108, 109, 0, 0x0L, EDVAL1, dpi, 47, 46, 30, 10},
-		{109, 110, 0, LASTOBJ, LTEXT, (void *) "dpi", 79, 46, 20, 8}};
+	void *dyndata[] = {(void*)"Image properties:", (void*)"width", (void*)width,
+		(void*)"height", (void*)height, (void*)"resolution", (void*)dpi,  (void *) "dpi"};
+	DlgInfo *ResDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
 	int res;
 	
+	if(!(ResDlg = CompileDialog(ResDlg_Tmpl, dyndata))) return false;
 	if(!(Dlg = new DlgRoot(ResDlg, 0L))) return false;
-	if(!(hDlg = CreateDlgWnd(header, 50, 50, 300, 160, Dlg, 0x0L)))return false;
+	if(!(hDlg = CreateDlgWnd(header, 50, 50, 340, 160, Dlg, 0x0L)))return false;
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -4263,11 +4278,8 @@ bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
 			Dlg->GetValue(108, dpi);
 			}
 		}while (res < 0);
-	if(res == 1) {
-		bRet = true;
-		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	bRet = (res == 1);
+	CloseDlgWnd(hDlg);	delete Dlg;		free(ResDlg);
 	return bRet;
 }
 
diff --git a/TheDialog.h b/TheDialog.h
index aeed423..7c88fb8 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -109,7 +109,8 @@ typedef struct {
 
 class DlgRoot:public tag_DlgObj {
 public:
-	anyOutput *CurrDisp;
+	anyOutput *CurrDisp;		//the dialog's output class
+	void *hDialog;				//handle to the dialog window/widget
 
 	DlgRoot(DlgInfo *tmpl, DataObj *d);
 	~DlgRoot();
@@ -137,8 +138,8 @@ public:
 	anyOutput *GetOutputClass(){return CurrDisp;};
 
 private:
+	int res_q[256], res_put, res_get, cDlgs, cContinue;
 	anyOutput *ParentOut;
-	int cDlgs, Result, cContinue;
 	DataObj *data;
 	Dialog *oldFocus, *oldDefault, *oldTabStop;
 	bool bActive, bRedraw;
diff --git a/UtilObj.cpp b/UtilObj.cpp
index 1512ddb..db976da 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -126,7 +126,7 @@ EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
 		}
 	text[i] = byte1;			CursorPos++;				type = ET_UNKNOWN;
 	Redraw(Out, true);
-	MyPos.y = loc.y;
+	MyPos.y = ((loc.y +crb.y)>>1);
 	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);
@@ -157,7 +157,8 @@ EditText::Update(int select, anyOutput *Out, POINT *MousePos)
 			bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
 			if(Out) {
 				Redraw(Out, true);
-				MyPos.y = loc.y;			MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
+				MyPos.y = ((loc.y +crb.y)>>1);
+				MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
 				if(MousePos && MousePos->x && MousePos->y) {
 					Out->TextCursor(text, MyPos, MousePos,&CursorPos, 
 					scroll_et == this ? scroll_dist : scroll_dist=0);
@@ -392,7 +393,7 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 	char *tag1, *tag2;
 	unsigned char *pt;
 
-	MyPos.y = loc.y;
+	MyPos.y = ((loc.y+crb.y)>>1);
 	MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
 	if(!(text)) return false;
 	if(!parent && disp) Out = disp;		//Dialog !
@@ -763,13 +764,12 @@ EditText::GetValue(double *v)
 		if(!(type & ET_BUSY)){
 			type |= ET_BUSY;
 			if(res = do_formula((DataObj*)parent, text+1)) {
-				if(res->type == ET_VALUE) Value = res->value;
-				else Value = 0.0;
-				*v = Value;		type &= ~ET_BUSY;
-				return res->type == ET_VALUE;
+				if(res->type == ET_VALUE || res->type == ET_DATE || res->type == ET_TIME 
+					|| res->type == ET_DATETIME || res->type == ET_BOOL){
+					*v = Value = res->value;	type &= ~ET_BUSY;	return true;
+					}
 				}
-			type &= ~ET_BUSY;
-			return false;
+			*v = Value = 0.0;	type &= ~ET_BUSY;	return false;
 			}
 		else type |= ET_CIRCULAR;
 		*v = Value;
@@ -1010,9 +1010,15 @@ EditText::set_etracc()
 		accept_range = (i && text && text[0] == '=' && text[i-1]!=')'
 			&& text[i-1] > 31 && !(isdigit(text[i-1]) || isalpha(text[i-1])));
 		if(accept_range) {
+			LockData(true, true);
 			res = do_formula((DataObj*)parent, text+1);
 			if(res->type != ET_ERROR) accept_range = false;
+			if(!accept_range) {
+				if(text[i-1] == '(' || text[i-1] == ',' || text[i-1] == ';')
+					accept_range = true;
+				}
 			((DataObj*)parent)->Command(CMD_CLEAR_ERROR, 0L, 0L);
+			LockData(false, false);
 			}
 		((DataObj*)parent)->Command(CMD_ETRACC, accept_range ? this : 0L, 0L);
 		}
@@ -1061,15 +1067,17 @@ 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;
+	src=0L;		split_text=0L;		split_text_W = 0;
+	n_split = n_split_W = uc_state = 0;
+	pos.x = pos.y = 0;				flags =0x0;
 }
 
 fmtText::fmtText(anyOutput *o, int x, int y, char *txt)
 {
 	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();
+	else src = 0L;		split_text = 0L;	split_text_W = 0L;
+	n_split = n_split_W = uc_state = 0;		flags = 0x0;
+	pos.x = x;	pos.y = y;		if(src)Parse();
 	if(o) DrawText(o);
 }
 
@@ -1096,7 +1104,6 @@ fmtText::StyleAt(int idx, TextDEF *txt_def, int *style, int *font)
 	return true;
 }
 
-
 int
 fmtText::rightTag(char *txt, int cb)
 {
@@ -1166,7 +1173,7 @@ fmtText::cur_right(int *pos)
 {
 	int n, tl;
 
-	if(!src || !pos || !src[*pos]) return;
+	if(!src || !pos || *pos >= (int)strlen(src) || !src[*pos]) return;
 	if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
 		*pos += (int)strlen(tags[n].tag);
 		cur_right(pos);
@@ -1184,6 +1191,9 @@ fmtText::cur_left(int *pos)
 
 	if(!src || !pos || !(*pos)) return;
 	(*pos)--;
+	if(*pos >= (n=(int)strlen(src))){
+		*pos = n-1;		return;
+		}
 	if(src[*pos] == ';' && (n=ucLeft(src, *pos, &tl, 0L)) == UC_TAG) {
 		*pos -= tl;		return;
 		}
@@ -1208,6 +1218,10 @@ fmtText::oGetTextExtent(anyOutput *o, int *width, int *height, int cb)
 			o->oGetTextExtentW((w_char*)(&split_text[i].uc), 1, &w1, &h1);
 			w += w1;		h = h1 > h ? h1 : h;
 			l += split_text[i].uc_len;
+			if (l >= cb) {
+				*width = w;		*height = h;	o->SetTextSpec(&td1);
+				return true;
+				}
 			}
 		else {
 			if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
@@ -1245,6 +1259,12 @@ 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(split_text_W) {
+		for(i = 0; i < n_split_W; i++) {
+			if(split_text_W[i].uc_txt) free((split_text_W[i].uc_txt));
+			}
+		free(split_text_W);		split_text_W = 0L;	n_split_W = 0;
+		}
 	if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
 	if(src)Parse();
 	if(o) DrawText(o);
@@ -1282,12 +1302,14 @@ fmtText::Parse()
 	char *tmp;
 
 	if((flags & 0x01) || !src || !(tmp = (char*)memdup(src, (int)strlen(src)+1, 0))) return false;
-	for(i = li = 0; src[i]; i++) {
+	for(i = li = uc_state = 0; src[i]; i++) {
 		if(i-li == 1 && split_text) {
 			if(src[li] == '<' && (n=rightTag(src, li))>=0) i--;
 			else if(src[li] == '&' && (n=ucTag(src, li, &tl, &uc))>0) i--;
 			}
 		if(src[i] == '<' && (n=rightTag(src, i))>=0) {
+			if(tags[n].font == FONT_GREEK) uc_state |= 0x02;
+			if(tags[n].op) uc_state |= 0x04;
 			if(split_text) {				//more tags in text
 				if(!(split_text = (fmt_txt_info *)realloc(split_text, (n_split+1)*sizeof(fmt_txt_info)))){
 					free(tmp);					return false;
@@ -1310,6 +1332,7 @@ fmtText::Parse()
 			li = i;							i--;
 			}
 		else if(src[i] == '&' && (n=ucTag(src, i, &tl, &uc))>0) {
+			uc_state |= 0x01;
 			if(split_text) {				//more tags in text
 				if(!(split_text = (fmt_txt_info *)realloc(split_text, (n_split+1)*sizeof(fmt_txt_info)))){
 					free(tmp);					return false;
@@ -1401,16 +1424,80 @@ fmtText::DrawBullet(anyOutput *o, int x, int y, int type, double size, DWORD lc,
 		}
 }
 
-void 
-fmtText::DrawFormatted(anyOutput *o)
+static int char2uc(char*src, w_char* dest, bool isGreek)
 {
-	int i, n, x, y, x1, y1, w, h;
-	TextDEF td1, td2;
-	double si, csi, fx, fy;
-	w_char one_uc[2];
+	int i;
 
-	if(!o || !split_text) return;
+	if(!src || !*src) return 0;
+	for(i = 0; ; i++){
+		if(isGreek && src[i] >= 'A' && src[i] <= 'Z') dest[i] = (src[i] - 'A' + 0x391);
+		else if(isGreek && src[i] >= 'a' && src[i] <= 'z') dest[i] = (src[i] - 'a' + 0x3B1);
+		else dest[i] = (src[i]);
+		if(!dest[i]) return i;
+		}
+}
+
+bool 
+fmtText::DrawFormattedW(anyOutput *o)
+{
+	int i, j, n, cb, x, y, x1, y1, w, h;
+	double si, csi, fx, fy;
+	TextDEF td1, td2;
+	bool bGreek = false;
+	
+	if(!o || !(split_text_W = (fmt_uc_info *)calloc(n_split, sizeof(fmt_uc_info))))return false;
 	memcpy(&td1, &o->TxtSet, sizeof(TextDEF));	memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
+	bGreek = (td1.Font == FONT_GREEK);
+	for(i = n_split_W = 0; i < n_split; i++){
+		if(split_text[i].tag == UC_TAG) {
+			if(i) {
+				j = n_split_W ? n_split_W-1 : 0;
+				cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+				if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt, 
+					(10 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+					split_text_W[j].uc_txt[split_text_W[j].cb++] = split_text[i].uc;
+					if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W[j].uc_txt+split_text_W[j].cb, bGreek);
+					split_text_W[j].uc_txt[split_text_W[j].cb] = 0;
+					}
+				}
+			else {
+				split_text_W[0].cb = 1;				split_text_W[0].tag = -1;
+				if(split_text_W[0].uc_txt = (w_char*)malloc(2*sizeof(w_char))) {
+					split_text_W[0].uc_txt[0] = split_text[0].uc;
+					split_text_W[0].uc_txt[0] = 0;
+					}
+				}
+			}
+		else if(split_text[i].tag >= 0 && tags[split_text[i].tag].font == FONT_GREEK) {
+			if(!i) return false;	bGreek = true;
+			j = n_split_W-1;		cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+			if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt, 
+				(2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+				if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
+				}
+			}
+		else if(bGreek && split_text[i].tag >= 0 && tags[split_text[i].tag].font == -2){
+			if(!i) return false;	bGreek = false;
+			j = n_split_W-1;		cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+			if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt, 
+				(2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+				if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
+				}
+			}
+		else {
+			if((n=split_text[i].tag) >= 0) SetTextDef(&td2, n);
+			bGreek = (td2.Font == FONT_GREEK);
+			split_text_W[n_split_W].tag = split_text[i].tag;
+			split_text_W[n_split_W].cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+			if(split_text_W[n_split_W].cb && (split_text_W[n_split_W].uc_txt = 
+				(w_char*)malloc((1 + split_text_W[n_split_W].cb) * sizeof(w_char)))) {
+				char2uc(split_text[i].txt, split_text_W[n_split_W].uc_txt, bGreek);
+				}
+			else split_text_W[n_split_W].uc_txt = 0L;
+			n_split_W++;
+			}
+		}
+	memcpy(&td2, &td1, sizeof(TextDEF));
 	si = sin(td1.RotBL *0.01745329252);	csi = cos(td1.RotBL *0.01745329252);
 	fx = pos.x;		fy = pos.y;	
 	oGetTextExtent(o, &w, &h, 0);
@@ -1422,14 +1509,8 @@ fmtText::DrawFormatted(anyOutput *o)
 		}
 	x = iround(fx);			y = iround(fy);
 	td2.Align &= ~(TXA_HRIGHT | TXA_HCENTER);			o->SetTextSpec(&td2);
-	for(i = 0; i < n_split; i++) if(split_text[i].txt || split_text[i].tag == UC_TAG) {
-		if(split_text[i].tag == UC_TAG) {
-			one_uc[0] = split_text[i].uc;	one_uc[1] = 0;
-			o->oGetTextExtentW(one_uc, 1, &w, &h);
-			if(!(o->oTextOutW(x, y, one_uc, 1))) o->oTextOut(x, y, "?", 1);
-			x = iround(fx += (w*csi));		y = iround(fy -= (w*si));
-			}
-		else if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
+	for(i = 0; i < n_split_W; i++) {
+		if((n=split_text_W[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
 		else if(n >= 0 && tags[n].op) {
 			x1 = x + iround(o->un2fix(td2.fSize*0.25)*csi);
 			y1 = y - iround(o->un2fiy(td2.fSize*0.25)*si);
@@ -1464,6 +1545,38 @@ fmtText::DrawFormatted(anyOutput *o)
 				}
 			o->SetTextSpec(&td2);
 			}
+		if(split_text_W[i].uc_txt && split_text_W[i].uc_txt[0]){
+			o->oTextOutW(x, y, split_text_W[i].uc_txt, 0);
+			o->oGetTextExtentW(split_text_W[i].uc_txt, 0, &w, &h);
+			x = iround(fx += (w*csi));		y = iround(fy -= (w*si));
+			}
+		}
+	return true;
+}
+
+void 
+fmtText::DrawFormatted(anyOutput *o)
+{
+	int i, n, x, y, w, h;
+	TextDEF td1, td2;
+	double si, csi, fx, fy;
+
+	if(!o || !split_text) return;
+	if(uc_state && DrawFormattedW(o)) return;
+	memcpy(&td1, &o->TxtSet, sizeof(TextDEF));	memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
+	si = sin(td1.RotBL *0.01745329252);	csi = cos(td1.RotBL *0.01745329252);
+	fx = pos.x;		fy = pos.y;	
+	oGetTextExtent(o, &w, &h, 0);
+	if(td2.Align & TXA_HRIGHT) {
+		fx -= w*csi;		fy += w*si;
+		}
+	else if(td2.Align & TXA_HCENTER){
+		fx -= (w>>1)*csi;	fy += (w>>1)*si;
+		}
+	x = iround(fx);			y = iround(fy);
+	td2.Align &= ~(TXA_HRIGHT | TXA_HCENTER);			o->SetTextSpec(&td2);
+	for(i = 0; i < n_split; i++) if(split_text[i].txt || split_text[i].tag == UC_TAG) {
+		if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
 		if(split_text[i].txt && split_text[i].txt[0]){
 			o->oTextOut(x, y, split_text[i].txt, 0);
 			o->oGetTextExtent(split_text[i].txt, 0, &w, &h);
@@ -2291,6 +2404,8 @@ AccRange::RangeDesc(void *d, int style)
 		if(res.text && res.text[0])
 			return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
 		else return 0L;
+	case ET_VALUE:
+		if(style != 4) break;
 	case ET_DATE:	case ET_DATETIME:	case ET_TIME:
 		TranslateResult(&res);
 		if(res.text && res.text[0])
@@ -2491,8 +2606,8 @@ Default::Default()
 	OutLine_0.color = OutLine_1.color = OutLine_2.color = 0x00000000L;
 	OutLine_0.pattern = OutLine_1.pattern = OutLine_2.pattern = 0L;
 	pl = pgl = 0L;	pg = 0L;	pg_fl = 0L;	rrect_rad = 0L;
-	cdisp = 0L;		min4log = 0.000001;		ss_txt = 0.9;
-	axis_color = 0x0L;	
+	cdisp = 0L;		min4log = 0.000001;		axis_color = 0x0L;
+	ss_txt = 0.9;
 	svgAttr = svgScript = currPath = IniFile = 0L;
 	File1 = File2 = File3 = File4 = File5 = File6 = 0L;
 	if(fmt_date = (char*)malloc(20)) rlp_strcpy(fmt_date, 20, "Z.V.Y");
@@ -2577,7 +2692,12 @@ Default::GetSize(int select)
 	case SIZE_HAIRLINE:				RetVal = 0.1;				break;
 	case SIZE_SEGLINE:				RetVal = 0.4;				break;
 	case SIZE_CELLWIDTH:			RetVal = 20.0;				break;
-	case SIZE_CELLTEXT:				RetVal = 4.5*ss_txt;		break;
+	case SIZE_CELLTEXT:
+#ifdef _WINDOWS
+		RetVal = 4.5*ss_txt;		break;
+#else
+		RetVal = 4.5*ss_txt*0.7;	break;
+#endif
 	case SIZE_RRECT_RAD:			
 		return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL);
 	case SIZE_SCALE:				return 1.0;
@@ -3394,6 +3514,7 @@ void
 UndoObj::DeleteGO(GraphObj **go, DWORD flags, anyOutput *o)
 {
 	if(!go || !(*go)) return;
+	HideCopyMark();
 	if(o){
 		SetDisp(o);					 o->HideMark();
 		}
diff --git a/Utils.cpp b/Utils.cpp
index 66bea56..ca15ccd 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -80,43 +80,40 @@ void NiceAxis(AxisDEF *axis, int nTick)
 		}
 	if(diff <= 0.0) return;
 	logStep = log10(diff/(double)nTick);
-	Magn = floor(logStep);
-	logStep -= Magn;
-	Step = 1.0;
-	if(logStep > 0.301) Step = 2.0; 
-	if(logStep > 0.699) Step = 5.0;
-	Step *= pow(10.0, Magn);
-	HiVal = LoVal = Step * floor(axis->min/Step);
-	axis->max *=1.05f;
+	Magn = floor(logStep);			logStep -= Magn;
+	if(logStep > 0.8) Step = 10.0;
+	else if(logStep > 0.5) Step = 5.0;
+	else if(logStep > 0.2) Step = 2.0; 
+	else Step = 1.0;
+	Step *= pow(10.0, Magn);		HiVal = LoVal = Step * floor(axis->min/Step);
+	axis->max += (diff * 0.05);
 	while(HiVal < axis->max) HiVal += Step;
 	if((axis->flags & AXIS_LOG) == AXIS_LOG) {
 		if (LoVal > defs.min4log) axis->min = LoVal;
 		if ((LoVal + Step) > defs.min4log && (LoVal + Step) < axis->min) axis->min = LoVal+Step;
 		}
 	else axis->min = LoVal;
-	axis->max = HiVal;
-	axis->Start = axis->min;
-	axis->Step = Step;
+	axis->max = HiVal;		axis->Start = axis->min;		axis->Step = Step;
 }
 
 void NiceStep(AxisDEF *axis, int nTick)
 {
-	double diff, logStep, Step, Magn;
+	double diff, d, logStep, Step, Magn;
 	int i;
 
-	diff = axis->max - axis->min;
+	diff = axis->max - axis->min;		d = axis->Step != 0.0 ? diff/axis->Step : HUGE_VAL;
+	if((d - floor(d)) < 0.1 && axis->Step != 0.0 && diff/axis->Step < 12.0)return;
 	if(axis->breaks) for(i = 0; i < axis->nBreaks; i++) {
 		diff -= fabs(axis->breaks[i].fy - axis->breaks[i].fx);
 		}
-	if(diff < 0.0) return;
+	if(diff <= 0.0) return;
 	logStep = log10(diff/(double)nTick);
-	Magn = floor(logStep);
-	logStep -= Magn;
-	Step = 1.0;
-	if(logStep > 0.301) Step = 2.0; 
-	if(logStep > 0.699) Step = 5.0;
-	Step *= pow(10.0, Magn);
-	axis->Step = Step;
+	Magn = floor(logStep);				logStep -= Magn;
+	if(logStep > 0.8) Step = 10.0;
+	else if(logStep > 0.5) Step = 5.0;
+	else if(logStep > 0.2) Step = 2.0; 
+	else Step = 1.0;
+	Step *= pow(10.0, Magn);			axis->Step = Step;
 }
 
 double base4log(AxisDEF *axis, int direc)
@@ -524,6 +521,18 @@ double NiceValue(double fv)
 	return sign*pow(10.0, magn-1.0) *(double)i;
 }
 
+char *NiceTime(double val)
+{
+	rlp_datetime dt;
+
+	parse_datevalue(&dt, val);
+	if(dt.year > 1905) {
+		if(dt.hours) return date2text(&dt, defs.fmt_datetime);
+		else return date2text(&dt, defs.fmt_date);
+		}
+	else return date2text(&dt, defs.fmt_time);
+}
+
 char *Int2ColLabel(int nr1, bool uc)
 {
 	static char RetTxt[12];
@@ -1100,7 +1109,7 @@ POINT *MakeArc(int ix, int iy, int r, int qad, long *npts)
 			}
 		}
 	if(*npts < 3) return 0L;
-	if(rpts = (POINT*)realloc(pts, sizeof(POINT)*(*npts))) return rpts;
+	if(rpts = (POINT*)realloc(pts, sizeof(POINT)*(*npts+4))) return rpts;
 	return pts;
 }
 
diff --git a/Version.h b/Version.h
index 2e349aa..5b444bb 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.3"
+#define SZ_VERSION  "1.4"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index a51b74b..1b1bcb3 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -300,14 +300,14 @@ void Qt_Box()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Display blinking text cursor
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-anyOutput *oTxtCur = 0L, *oCopyMark = 0L;
+static anyOutput *oTxtCur = 0L, *oCopyMark = 0L;
 RECT rTxtCur, rCopyMark;
-bool bTxtCur = false, bTxtCurIsVis = false, bSuspend = false;
-DWORD cTxtCur = 0x0L;
-HWND hwndTxtCur = 0L;
-int iTxtCurCount = 0;
-POINT ptTxtCurLine[2];
-BitMapWin *bmCopyMark = 0L;
+static bool bTxtCur = false, bTxtCurIsVis = false, bSuspend = false;
+static DWORD cTxtCur = 0x0L;
+static HWND hwndTxtCur = 0L;
+static int iTxtCurCount = 0;
+static POINT ptTxtCurLine[2];
+static BitMapWin *bmCopyMark = 0L;
 
 void HideTextCursor()
 {
@@ -340,10 +340,12 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
 
 void HideCopyMark()
 {
+	BitMapWin *CurrCopyMark;
+
 	if(bmCopyMark && oCopyMark) {
-		bmCopyMark = 0L;
+		CurrCopyMark = bmCopyMark;		bmCopyMark = 0L;
 		oCopyMark->UpdateRect(&rCopyMark, false);
-		delete bmCopyMark;
+		delete CurrCopyMark;
 		}
 	bmCopyMark = 0L;	oCopyMark = 0L;
 }
@@ -388,8 +390,8 @@ void SuspendAnimation(anyOutput *o, bool bSusp)
 		}
 }
 
-LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
-LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
+static LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
+static LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
 
 LRESULT FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 {
@@ -688,6 +690,7 @@ bool com_oTextOut(int x, int y, char *atxt, int cb, HFONT *hFont, HDC *dc, TextD
 	unsigned char *utxt = (unsigned char*)atxt;
 	w_char *uc;
 	int i;
+	bool bRet;
 
 	if(!*hFont || !atxt || !atxt[0]) return false;
 	if(cb < 1) cb = (int)strlen(atxt);
@@ -699,12 +702,9 @@ bool com_oTextOut(int x, int y, char *atxt, int cb, HFONT *hFont, HDC *dc, TextD
 			else uc[i] = utxt[i];
 			}
 		}
-	else {
-		for(i = 0; utxt[i]; i++) uc[i] = utxt[i];
-		}
-	com_oTextOutW(x, y, uc, cb, hFont, dc, td, o);
-	free(uc);
-	return false;
+	else for(i = 0; utxt[i]; i++) uc[i] = utxt[i];
+	bRet = com_oTextOutW(x, y, uc, cb, hFont, dc, td, o);
+	free(uc);		return bRet;
 }
 
 bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet, 
@@ -1143,85 +1143,85 @@ OutputWin::Caption(char *txt)
 	SetWindowText(hWnd, txt);
 }
 
-unsigned char hand_bits[] =	{	//hand cursor bitmap
+const static unsigned char hand_bits[] =	{	//hand cursor bitmap
 	0x01, 0x80, 0x1b, 0xf0, 0x3f, 0xf8, 0x3f, 0xfa,
 	0x1f, 0xff, 0x1f, 0xff, 0x6f, 0xff, 0xff, 0xff,
 	0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc,
 	0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8};
 
-unsigned char hand_mask[] =	{	//hand cursor mask
+const static unsigned char hand_mask[] =	{	//hand cursor mask
 	0xff, 0xff, 0xfe, 0x7f, 0xe6, 0x4f, 0xe6, 0x4f,
 	0xf2, 0x4d, 0xf2, 0x49, 0x78, 0x09, 0x98, 0x01,
 	0x88, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07,
 	0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f};
 
-unsigned char zoom_bits[] =	{	//zoom cursor bitmap
+const static unsigned char zoom_bits[] =	{	//zoom cursor bitmap
 	0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x06, 0x30,
 	0x08, 0x08, 0x10, 0x84, 0x10, 0x84, 0x20, 0x02,
 	0x26, 0x32, 0x20, 0x02, 0x10, 0x84, 0x10, 0x84,
 	0x08, 0x08, 0x06, 0x30, 0x01, 0xa0, 0x00, 0x00};
 
-unsigned char zoom_mask[] =	{	//zoom cursor mask
+const static unsigned char zoom_mask[] =	{	//zoom cursor mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
-unsigned char paste_bits[] =	{	//paste cursor bitmap
+const static unsigned char paste_bits[] =	{	//paste cursor bitmap
 	0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00,
 	0x23, 0xfe, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff,
 	0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff,
 	0x07, 0xff, 0x07, 0xff, 0x03, 0xfe, 0x00, 0x00};
 
-unsigned char paste_mask[] =	{	//paste cursor mask
+const static unsigned char paste_mask[] =	{	//paste cursor mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xfc, 0x05, 0xfd, 0x05, 0xfd, 0xf9,
 	0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01,
 	0xfc, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff};
 
-unsigned char drawpen_bits[] =	{	//draw cursor bitmap
+const static unsigned char drawpen_bits[] =	{	//draw cursor bitmap
 	0xc0, 0x00, 0xf0, 0x00, 0x7c, 0x00, 0x7f, 0x00,
 	0x3f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x1f, 0xf0,
 	0x0f, 0xf8, 0x07, 0xfc, 0x03, 0xfe, 0x01, 0xff,
 	0x00, 0xff, 0x00, 0x7e, 0x00, 0x3c, 0x00, 0x18};
 
-unsigned char drawpen_mask[] =	{	//draw cursor mask
+const static unsigned char drawpen_mask[] =	{	//draw cursor mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff,
 	0xe0, 0xff, 0xe2, 0x7f, 0xf1, 0x3f, 0xf0, 0x9f,
 	0xf8, 0x4f, 0xfc, 0x27, 0xfe, 0x13, 0xff, 0x0b,
 	0xff, 0x87, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff};
 
-unsigned char drect_bits[] =	{	//draw rectangle bitmap
+const static unsigned char drect_bits[] =	{	//draw rectangle bitmap
 	0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00,
 	0x20, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x1f, 0xff,
 	0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff,
 	0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x00, 0x00};
 
-unsigned char drect_mask[] =	{	//draw rectangle mask
+const static unsigned char drect_mask[] =	{	//draw rectangle mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x01,
 	0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01,
 	0xf0, 0x01, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff};
 
-unsigned char drrect_bits[] =	{	//draw rounded rectangle bitmap
+const static unsigned char drrect_bits[] =	{	//draw rounded rectangle bitmap
 	0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00,
 	0x20, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x0f, 0xfe,
 	0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff,
 	0x1f, 0xff, 0x0f, 0xfe, 0x07, 0xfc, 0x00, 0x00};
 
-unsigned char drrect_mask[] =	{	//draw rounded rectangle mask
+const static unsigned char drrect_mask[] =	{	//draw rounded rectangle mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03,
 	0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01,
 	0xf0, 0x01, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff};
 
-unsigned char delly_bits[] =	{	//draw ellipse bitmap
+const static unsigned char delly_bits[] =	{	//draw ellipse bitmap
 	0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00,
 	0x20, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x07, 0xfc,
 	0x0f, 0xfe, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff,
 	0x0f, 0xfe, 0x07, 0xfc, 0x01, 0xf0, 0x00, 0x00};
 
-unsigned char delly_mask[] =	{	//draw ellipse mask
+const static unsigned char delly_mask[] =	{	//draw ellipse mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f,
 	0xf8, 0x03, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01,
@@ -1426,7 +1426,7 @@ OutputWin::ShowEllipse(POINT p1, POINT p2, DWORD color)
 bool
 OutputWin::SetMenu(int type)
 {
-	HMENU hMenu = 0L;
+	HMENU hMenu = 0L, hPopup = 0L;
 
 	switch(type) {
 	case MENU_NONE:
@@ -1435,7 +1435,13 @@ OutputWin::SetMenu(int type)
 		hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_2));
 		break;
 	case MENU_GRAPH:
-		hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_1));
+/*
+		hMenu = CreateMenu();
+		hPopup = CreatePopupMenu();
+		AppendMenu(hPopup, MF_STRING, CM_OPEN, "&Open");
+		AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hPopup, "&File");
+//		AppendMenu(hMenu, MF_POPUP, (unsigned int)hPopup, "&File");
+//*/		hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_1));
 		break;
 	case MENU_PAGE:
 		hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_3));
@@ -1764,20 +1770,14 @@ PrintWin::PrintWin()
 	double pw, ph;
 
 	PrintDriver = PrintDevice = PrintPort = 0L;
-	hPen = 0L;
-	hBrush = 0L;
-	hFont = 0L;
-	hDC = 0L;
-	hgo = 0L;
-	units = defs.cUnits;
-	i = j = 0;
+	hPen = 0L;		hBrush = 0L;			hFont = 0L;		hDC = 0L;
+	hgo = 0L;		units = defs.cUnits;	i = j = 0;
 	GetProfileString("windows", "device", "", TmpTxt, 4096);
 	while(TmpTxt[i] && TmpTxt[i] != ',') i++;
 	TmpTxt[i] = 0;
 	if (i >2) {
 		PrintDevice = _strdup(TmpTxt);
-		i++;
-		j = i;
+		i++;			j = i;
 		while(TmpTxt[i] && TmpTxt[i] != ',') i++;
 		if(i-j > 2) {
 			TmpTxt[i] = 0;
@@ -1810,12 +1810,9 @@ PrintWin::PrintWin()
 
 PrintWin::~PrintWin()
 {
-	if(PrintDriver) free(PrintDriver);
-	if(PrintDevice) free(PrintDevice);
-	if(PrintPort) free(PrintPort);
-	if(hPen) DeleteObject(hPen);
-	if(hBrush) DeleteObject(hBrush);
-	if(hFont) DeleteObject(hFont);
+	if(PrintDriver) free(PrintDriver);		if(PrintDevice) free(PrintDevice);
+	if(PrintPort) free(PrintPort);			if(hPen) DeleteObject(hPen);
+	if(hBrush) DeleteObject(hBrush);		if(hFont) DeleteObject(hFont);
 }
 
 bool
@@ -2227,12 +2224,16 @@ long OpenFileFromHistory(OutputWin *w, GraphObj *g, int id)
 	case 3:			name = defs.File4;			break;
 	case 4:			name = defs.File5;			break;
 	case 5:			name = defs.File6;			break;
+	default:		return 0;
 		}
-	if(name && FileExist(name)) {
+	if(name && name[0] && FileExist(name)) {
 		g->Command(CMD_DROPFILE, name, w);
 		defs.FileHistory(name);
 		w->FileHistory();
 		}
+	else {
+		ErrorBox("The selected file   \ndoes not exist!\n");
+		}
 	return 0;
 }
 
@@ -2343,6 +2344,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			SetCursor(LoadCursor(NULL, IDC_ARROW));
 		return 0;
 	case WM_DESTROYCLIPBOARD:
+		if(g && w) g->Command(CMD_HIDEMARK, 0L, w);
+		HideCopyMark();
 		return 0;
 	case WM_RENDERALLFORMATS:
 		// we do not support leaving data on the clipboard after exit
@@ -2402,9 +2405,17 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			return 0;
 		case CM_COPY:			case CM_CUT:		case CM_COPYGRAPH:
 			EmptyClip();
-			if(g->Id != GO_SPREADDATA && CurrGO && CurrGO->Id == GO_TEXTFRAME) {
-				if(CurrGO->Command(CMD_COPY, 0L, w))return 0;
-				}
+			if(CurrGO && g->Id != GO_SPREADDATA) {
+				if(CurrGO->Id == GO_POLYLINE || CurrGO->Id == GO_POLYGON || CurrGO->Id == GO_RECTANGLE
+					|| CurrGO->Id == GO_ROUNDREC || CurrGO->Id == GO_ELLIPSE || CurrGO->Id == GO_BEZIER) {
+					OpenClipboard(hwnd);
+					CopyGraph(CurrGO, cf_rlpobj, w);		copy_obj = CurrGO;
+					CloseClipboard();						return 0;
+					}
+				else if(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);
@@ -2418,6 +2429,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 					CopyGraph(CurrGraph, cf_rlpobj, w);		copy_obj = CurrGraph;
 					}
 				}
+			else if (wParam == CM_CUT)return 0;
 			else if(CurrGraph && CurrGraph->Id == GO_GRAPH){
 				SetClipboardData(CF_ENHMETAFILE, NULL);
 				SetClipboardData(CF_BITMAP, NULL);
@@ -2621,12 +2633,24 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_REPANOV:
 			if(g->data) rep_anova(g, g->data);
 			return 0;
+		case CM_REPTWANR:
+			if(g->data) rep_twoway_anova(g, g->data);
+			return 0;
 		case CM_REPKRUSKAL:
 			if(g->data) rep_kruskal(g, g->data);
 			return 0;
+		case CM_REPTWANOV:
+			if(g->data) rep_twanova(g, g->data);
+			return 0;
+		case CM_REPFRIEDM:
+			if(g->data) rep_fmanova(g, g->data);
+			return 0;
 		case CM_REPREGR:
 			if(g->data) rep_regression(g, g->data);
 			return 0;
+		case CM_ROBUSTLINE:
+			if(g->data) rep_robustline(g, g->data);
+			return 0;
 		case CM_CORRELM:
 			if(g->data) rep_correl(g, g->data, 0);
 			return 0;
@@ -2792,6 +2816,7 @@ 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)) {
+		((DlgRoot*)d)->hDialog = hDlg;
 		SetWindowLong(hDlg, GWL_USERDATA, lptrref(w));
 		SetWindowLong(hDlg, 0, lptrref(d));
 		if(flags & 0x01) {					//center on screen
diff --git a/menu.h b/menu.h
index dd3e9e9..00a49ed 100755
--- a/menu.h
+++ b/menu.h
@@ -95,8 +95,12 @@
 #define CM_SMPLSTAT    650
 #define CM_REPCMEANS   651
 #define CM_REPANOV     652
-#define CM_REPKRUSKAL  653
-#define CM_REPREGR     654
-#define CM_CORRELM     655
-#define CM_CORRELT     656
-#define CM_REPTWOWAY   657
+#define CM_REPTWANOV   653
+#define CM_REPFRIEDM   654
+#define CM_REPTWANR    655
+#define CM_REPKRUSKAL  656
+#define CM_REPREGR     657
+#define CM_ROBUSTLINE  658
+#define CM_CORRELM     659
+#define CM_CORRELT     660
+#define CM_REPTWOWAY   661
diff --git a/mfcalc.cpp b/mfcalc.cpp
old mode 100644
new mode 100755
index a7da92b..3b55224
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -35,35 +35,34 @@
 #define	AFNCT	285
 #define	SFNCT	286
 #define	FUNC1	287
-#define	FUNC2	288
-#define	FUNC3	289
-#define	TXT	290
-#define	SRFUNC	291
-#define	YYFNC	292
-#define	FUNC4	293
-#define	YYFNC2	294
-#define	YYFNC3	295
-#define	ADDEQ	296
-#define	SUBEQ	297
-#define	MULEQ	298
-#define	DIVEQ	299
-#define	CLAUSE	300
-#define	SER	301
-#define	COLC	302
-#define	AND	303
-#define	OR	304
-#define	EQ	305
-#define	NE	306
-#define	GT	307
-#define	GE	308
-#define	LT	309
-#define	LE	310
-#define	NEG	311
-#define	INC	312
-#define	DEC	313
-#define	PINC	314
-#define	PDEC	315
-#define	PDIM	316
+#define	TXT	288
+#define	SRFUNC	289
+#define	YYFNC	290
+#define	FUNC4	291
+#define	YYFNC2	292
+#define	YYFNC3	293
+#define	ADDEQ	294
+#define	SUBEQ	295
+#define	MULEQ	296
+#define	DIVEQ	297
+#define	LSEP	298
+#define	CLAUSE	299
+#define	SER	300
+#define	COLC	301
+#define	AND	302
+#define	OR	303
+#define	EQ	304
+#define	NE	305
+#define	GT	306
+#define	GE	307
+#define	LT	308
+#define	LE	309
+#define	NEG	310
+#define	INC	311
+#define	DEC	312
+#define	PINC	313
+#define	PDEC	314
+#define	PDIM	315
 
 
 /*
@@ -169,8 +168,9 @@ static char *last_err_desc = 0L;	//short error description
 static char *buffer = 0L;		//the current command buffer
 static int buff_pos = 0;
 static bool bRecent = false;		//rearrange functions
+static bool bNoWrite, bNoExec;		//while editing ...
 static int parse_level = 0;		//count reentrances into parser
-#define MAX_PARSE 20			//maximum number of reentances 
+#define MAX_PARSE 50			//maximum number of recursive reentances 
 #include <stdio.h>
 
 #ifndef __cplusplus
@@ -181,23 +181,23 @@ static int parse_level = 0;		//count reentrances into parser
 
 
 
-#define	YYFINAL		260
+#define	YYFINAL		243
 #define	YYFLAG		-32768
-#define	YYNTBASE	78
+#define	YYNTBASE	77
 
-#define YYTRANSLATE(x) ((unsigned)(x) <= 316 ? yytranslate[x] : 87)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 315 ? yytranslate[x] : 86)
 
 static const char yytranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    72,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    70,
      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,    74,
-    75,    62,    61,    47,    60,     2,    63,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,    77,    73,     2,
-    42,     2,    51,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    73,
+    74,    60,    59,    72,    58,     2,    61,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    76,    71,     2,
+    40,     2,    49,     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,
-    64,     2,    76,    65,     2,     2,     2,     2,     2,     2,
+    62,     2,    75,    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,     2,     2,     2,     2,     2,     2,     2,
@@ -217,9 +217,9 @@ static const char yytranslate[] = {     0,
      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,    32,    33,    34,    35,    36,
-    37,    38,    39,    40,    41,    43,    44,    45,    46,    48,
-    49,    50,    52,    53,    54,    55,    56,    57,    58,    59,
-    66,    67,    68,    69,    70,    71
+    37,    38,    39,    41,    42,    43,    44,    45,    46,    47,
+    48,    50,    51,    52,    53,    54,    55,    56,    57,    64,
+    65,    66,    67,    68,    69
 };
 
 #if YYDEBUG != 0
@@ -231,83 +231,81 @@ static const short yyprhs[] = {     0,
    141,   145,   149,   153,   157,   161,   163,   165,   167,   169,
    171,   173,   175,   177,   179,   181,   183,   185,   187,   191,
    195,   199,   203,   207,   211,   216,   221,   228,   237,   242,
-   247,   254,   261,   268,   275,   282,   289,   296,   303,   310,
-   319,   326,   335,   346,   353,   360,   364,   369,   376,   381,
-   390,   394,   398,   402,   406,   409,   412,   415,   418,   422,
-   425,   429,   435,   440,   447,   454,   461,   468,   475,   481,
-   485,   491,   497,   503
+   247,   254,   261,   268,   275,   282,   289,   296,   303,   314,
+   321,   328,   332,   337,   344,   349,   358,   365,   369,   373,
+   377,   381,   384,   387,   390,   393,   397,   400,   404,   410,
+   415,   422,   429,   436,   443,   450,   456,   460,   466,   472,
+   478
 };
 
 static const short yyrhs[] = {    -1,
-    78,    79,     0,    72,     0,    73,     0,    47,     0,    86,
-    72,     0,    86,    73,     0,    86,    47,     0,    80,    72,
-     0,    80,    73,     0,    14,     8,    84,     0,    14,     8,
-    84,    15,    84,     0,    23,     8,    84,     0,    22,     8,
-    84,     0,    26,     9,     0,    27,     0,     1,    72,     0,
-     5,     0,    80,    61,    86,     0,    86,    61,    80,     0,
-    80,    61,    80,     0,    37,    74,    86,    75,     0,    37,
-    74,    86,    13,    80,    75,     0,    37,    74,    86,    13,
-    86,    75,     0,    37,    74,    86,    47,    80,    75,     0,
-    37,    74,    86,    47,    86,    75,     0,    80,     0,     6,
-     0,    86,     0,    82,    47,    82,     0,    82,    48,    86,
-     0,    81,     0,     3,    49,     3,     0,     4,     0,    30,
-    74,    86,    75,     0,    16,     0,    17,     0,    86,    52,
-    86,     0,    86,    53,    86,     0,    86,    54,    86,     0,
-    86,    55,    86,     0,    86,    56,    86,     0,    86,    57,
-    86,     0,    86,    58,    86,     0,    86,    59,    86,     0,
-     7,     0,     9,     0,    86,     0,    80,     0,     3,     0,
-    25,     0,    83,     0,    36,     0,    12,     0,    10,     0,
-    11,     0,    28,     0,    84,     0,    28,    42,    86,     0,
-    28,    42,    80,     0,    28,    43,    86,     0,    28,    44,
-    86,     0,    28,    45,    86,     0,    28,    46,    86,     0,
-    29,    74,    86,    75,     0,    31,    74,    82,    75,     0,
-    31,    74,    86,    13,    82,    75,     0,    31,    74,    86,
-    13,    86,    13,    86,    75,     0,    32,    74,    80,    75,
-     0,    32,    74,    86,    75,     0,    32,    74,    80,    13,
-    80,    75,     0,    32,    74,    86,    13,    80,    75,     0,
-    32,    74,    86,    13,    86,    75,     0,    32,    74,    80,
-    13,    86,    75,     0,    32,    74,    80,    47,    80,    75,
-     0,    32,    74,    86,    47,    80,    75,     0,    32,    74,
-    80,    47,    86,    75,     0,    32,    74,    86,    47,    86,
-    75,     0,    34,    74,    85,    13,    85,    75,     0,    34,
-    74,    85,    13,    85,    13,    85,    75,     0,    35,    74,
-    82,    13,    82,    75,     0,    35,    74,    82,    13,    82,
-    13,    81,    75,     0,    39,    74,    86,    13,    86,    13,
-    82,    13,    81,    75,     0,    33,    74,    82,    13,    81,
-    75,     0,    33,    74,    82,    13,    25,    75,     0,    38,
-    74,    75,     0,    38,    74,    82,    75,     0,    40,    74,
-    85,    13,    85,    75,     0,    40,    74,    85,    75,     0,
-    41,    74,    85,    13,    85,    13,    85,    75,     0,    86,
-    61,    86,     0,    86,    60,    86,     0,    86,    62,    86,
-     0,    86,    63,    86,     0,    28,    67,     0,    28,    68,
-     0,    67,    28,     0,    68,    28,     0,    86,    65,    86,
-     0,    60,    86,     0,    74,    85,    75,     0,    21,    28,
-    64,    86,    76,     0,    86,    64,    86,    76,     0,    86,
-    64,    86,    76,    42,    86,     0,    86,    64,    86,    76,
-    43,    86,     0,    86,    64,    86,    76,    44,    86,     0,
-    86,    64,    86,    76,    45,    86,     0,    86,    64,    86,
-    76,    46,    86,     0,     3,    77,     3,    77,     3,     0,
-     3,    77,     3,     0,    86,    51,    86,    50,    86,     0,
-    86,    51,     5,    50,     5,     0,    86,    51,     5,    50,
-    86,     0,    86,    51,    86,    50,     5,     0
+    77,    78,     0,    70,     0,    71,     0,    72,     0,    85,
+    70,     0,    85,    71,     0,    85,    72,     0,    79,    70,
+     0,    79,    71,     0,    14,     8,    83,     0,    14,     8,
+    83,    15,    83,     0,    23,     8,    83,     0,    22,     8,
+    83,     0,    26,     9,     0,    27,     0,     1,    70,     0,
+     5,     0,    79,    59,    85,     0,    85,    59,    79,     0,
+    79,    59,    79,     0,    35,    73,    85,    74,     0,    35,
+    73,    85,    13,    79,    74,     0,    35,    73,    85,    13,
+    85,    74,     0,    35,    73,    85,    72,    79,    74,     0,
+    35,    73,    85,    72,    85,    74,     0,    79,     0,     6,
+     0,    85,     0,    81,    45,    81,     0,    81,    46,    85,
+     0,    80,     0,     3,    47,     3,     0,     4,     0,    30,
+    73,    85,    74,     0,    16,     0,    17,     0,    85,    50,
+    85,     0,    85,    51,    85,     0,    85,    52,    85,     0,
+    85,    53,    85,     0,    85,    54,    85,     0,    85,    55,
+    85,     0,    85,    56,    85,     0,    85,    57,    85,     0,
+     7,     0,     9,     0,    85,     0,    79,     0,     3,     0,
+    25,     0,    82,     0,    34,     0,    12,     0,    10,     0,
+    11,     0,    28,     0,    83,     0,    28,    40,    85,     0,
+    28,    40,    79,     0,    28,    41,    85,     0,    28,    42,
+    85,     0,    28,    43,    85,     0,    28,    44,    85,     0,
+    29,    73,    85,    74,     0,    31,    73,    81,    74,     0,
+    31,    73,    85,    13,    81,    74,     0,    31,    73,    85,
+    13,    85,    13,    85,    74,     0,    32,    73,    79,    74,
+     0,    32,    73,    85,    74,     0,    32,    73,    79,    13,
+    79,    74,     0,    32,    73,    85,    13,    79,    74,     0,
+    32,    73,    85,    13,    85,    74,     0,    32,    73,    79,
+    13,    85,    74,     0,    32,    73,    79,    72,    79,    74,
+     0,    32,    73,    85,    72,    79,    74,     0,    32,    73,
+    79,    72,    85,    74,     0,    32,    73,    85,    72,    85,
+    74,     0,    37,    73,    85,    13,    85,    13,    81,    13,
+    80,    74,     0,    33,    73,    81,    13,    80,    74,     0,
+    33,    73,    81,    13,    25,    74,     0,    36,    73,    74,
+     0,    36,    73,    81,    74,     0,    38,    73,    84,    13,
+    84,    74,     0,    38,    73,    84,    74,     0,    39,    73,
+    84,    13,    84,    13,    84,    74,     0,    39,    73,    84,
+    13,    84,    74,     0,    85,    59,    85,     0,    85,    58,
+    85,     0,    85,    60,    85,     0,    85,    61,    85,     0,
+    28,    65,     0,    28,    66,     0,    65,    28,     0,    66,
+    28,     0,    85,    63,    85,     0,    58,    85,     0,    73,
+    84,    74,     0,    21,    28,    62,    85,    75,     0,    85,
+    62,    85,    75,     0,    85,    62,    85,    75,    40,    85,
+     0,    85,    62,    85,    75,    41,    85,     0,    85,    62,
+    85,    75,    42,    85,     0,    85,    62,    85,    75,    43,
+    85,     0,    85,    62,    85,    75,    44,    85,     0,     3,
+    76,     3,    76,     3,     0,     3,    76,     3,     0,    85,
+    49,    85,    48,    85,     0,    85,    49,     5,    48,     5,
+     0,    85,    49,     5,    48,    85,     0,    85,    49,    85,
+    48,     5,     0
 };
 
 #endif
 
 #if YYDEBUG != 0
 static const short yyrline[] = { 0,
-   135,   136,   139,   139,   139,   140,   141,   142,   143,   144,
-   145,   147,   150,   151,   153,   154,   155,   158,   160,   161,
-   162,   163,   164,   165,   166,   167,   170,   174,   175,   176,
-   177,   178,   179,   183,   184,   185,   186,   187,   188,   189,
-   190,   191,   192,   193,   194,   197,   197,   199,   199,   201,
-   202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
-   212,   213,   214,   215,   217,   218,   219,   221,   224,   225,
-   226,   227,   228,   229,   230,   231,   232,   233,   234,   235,
-   236,   237,   238,   239,   240,   241,   242,   243,   244,   245,
-   246,   250,   254,   255,   257,   258,   259,   260,   261,   262,
-   263,   264,   266,   268,   270,   273,   276,   279,   283,   284,
-   285,   286,   287,   288
+   136,   137,   140,   140,   140,   141,   142,   143,   144,   145,
+   146,   148,   151,   152,   154,   155,   156,   159,   161,   162,
+   163,   164,   165,   166,   167,   168,   171,   175,   176,   177,
+   178,   179,   180,   184,   185,   186,   187,   188,   189,   190,
+   191,   192,   193,   194,   195,   198,   198,   200,   200,   202,
+   203,   204,   205,   206,   207,   208,   209,   210,   211,   212,
+   213,   214,   215,   216,   218,   219,   220,   222,   225,   226,
+   227,   228,   229,   230,   231,   232,   233,   234,   235,   236,
+   237,   238,   239,   240,   241,   242,   243,   244,   248,   252,
+   253,   255,   256,   257,   258,   259,   260,   261,   262,   264,
+   266,   270,   274,   278,   282,   287,   288,   289,   290,   291,
+   292
 };
 #endif
 
@@ -317,28 +315,28 @@ static const short yyrline[] = { 0,
 static const char * const yytname[] = {   "$","error","$undefined.","NUM","BOOLVAL",
 "STR","ARR","BLOCK","PBLOCK","IBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE",
 "BFALSE","DATE1","TIME1","DATETIME1","DIM","WHILE","FOR","INARR","RANGEARR",
-"RETURN","BREAK","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","FUNC2","FUNC3",
-"TXT","SRFUNC","YYFNC","FUNC4","YYFNC2","YYFNC3","'='","ADDEQ","SUBEQ","MULEQ",
-"DIVEQ","','","CLAUSE","SER","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT",
-"LE","'-'","'+'","'*'","'/'","'['","'^'","NEG","INC","DEC","PINC","PDEC","PDIM",
-"'\\n'","';'","'('","')'","']'","':'","input","line","str_exp","range","arr",
-"bool","block","anyarg","exp", NULL
+"RETURN","BREAK","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","TXT","SRFUNC",
+"YYFNC","FUNC4","YYFNC2","YYFNC3","'='","ADDEQ","SUBEQ","MULEQ","DIVEQ","LSEP",
+"CLAUSE","SER","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT","LE","'-'","'+'",
+"'*'","'/'","'['","'^'","NEG","INC","DEC","PINC","PDEC","PDIM","'\\n'","';'",
+"','","'('","')'","']'","':'","input","line","str_exp","range","arr","bool",
+"block","anyarg","exp", NULL
 };
 #endif
 
 static const short yyr1[] = {     0,
-    78,    78,    79,    79,    79,    79,    79,    79,    79,    79,
-    79,    79,    79,    79,    79,    79,    79,    80,    80,    80,
-    80,    80,    80,    80,    80,    80,    81,    82,    82,    82,
-    82,    82,    82,    83,    83,    83,    83,    83,    83,    83,
-    83,    83,    83,    83,    83,    84,    84,    85,    85,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
-    86,    86,    86,    86
+    77,    77,    78,    78,    78,    78,    78,    78,    78,    78,
+    78,    78,    78,    78,    78,    78,    78,    79,    79,    79,
+    79,    79,    79,    79,    79,    79,    80,    81,    81,    81,
+    81,    81,    81,    82,    82,    82,    82,    82,    82,    82,
+    82,    82,    82,    82,    82,    83,    83,    84,    84,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85,    85,    85,    85,    85,    85,    85,    85,    85,    85,
+    85
 };
 
 static const short yyr2[] = {     0,
@@ -349,325 +347,311 @@ static const short yyr2[] = {     0,
      3,     3,     3,     3,     3,     1,     1,     1,     1,     1,
      1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
      3,     3,     3,     3,     4,     4,     6,     8,     4,     4,
-     6,     6,     6,     6,     6,     6,     6,     6,     6,     8,
-     6,     8,    10,     6,     6,     3,     4,     6,     4,     8,
-     3,     3,     3,     3,     2,     2,     2,     2,     3,     2,
-     3,     5,     4,     6,     6,     6,     6,     6,     5,     3,
-     5,     5,     5,     5
+     6,     6,     6,     6,     6,     6,     6,     6,    10,     6,
+     6,     3,     4,     6,     4,     8,     6,     3,     3,     3,
+     3,     2,     2,     2,     2,     3,     2,     3,     5,     4,
+     6,     6,     6,     6,     6,     5,     3,     5,     5,     5,
+     5
 };
 
 static const short yydefact[] = {     1,
      0,     0,    50,    34,    18,    46,    47,    55,    56,    54,
      0,    36,    37,     0,     0,     0,    51,     0,    16,    57,
-     0,     0,     0,     0,     0,     0,     0,    53,     0,     0,
-     0,     0,     0,     5,     0,     0,     0,     3,     4,     0,
-     2,     0,    52,    58,     0,    17,     0,     0,     0,     0,
-     0,    15,     0,     0,     0,     0,     0,    95,    96,     0,
+     0,     0,     0,     0,     0,    53,     0,     0,     0,     0,
+     0,     0,     0,     0,     3,     4,     5,     0,     2,     0,
+    52,    58,     0,    17,     0,     0,     0,     0,     0,    15,
+     0,     0,     0,     0,     0,    92,    93,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,    97,    94,    95,
+    49,     0,    48,     0,     9,    10,     0,     0,     0,     0,
      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   100,    97,    98,    49,     0,    48,     0,     9,    10,
-     8,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     6,     7,   110,    11,
-     0,    14,    13,    60,    59,    61,    62,    63,    64,     0,
-     0,    50,    28,    27,    32,     0,    29,     0,     0,     0,
-    29,     0,     0,     0,    86,     0,     0,     0,     0,     0,
-   101,    21,    19,     0,     0,    38,    39,    40,    41,    42,
-    43,    44,    45,    92,    20,    91,    93,    94,     0,    99,
-     0,     0,     0,    65,    35,     0,     0,     0,    66,     0,
-     0,     0,    69,     0,     0,    70,     0,     0,     0,     0,
-     0,    22,    87,     0,     0,    89,     0,    91,     0,     0,
-   103,   109,    12,   102,    33,    30,    31,     0,    29,     0,
-     0,     0,     0,     0,     0,     0,     0,    51,     0,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,   112,
-   113,   114,   111,     0,     0,     0,     0,     0,    67,     0,
-    71,    74,    75,    77,    72,    73,    76,    78,    85,    84,
-     0,    79,     0,    81,    23,    24,    25,    26,     0,    88,
-     0,   104,   105,   106,   107,   108,     0,     0,     0,     0,
-     0,    68,    80,    82,     0,    90,     0,    83,     0,     0
+     0,     6,     7,     8,   107,    11,     0,    14,    13,    60,
+    59,    61,    62,    63,    64,     0,     0,    50,    28,    27,
+    32,     0,    29,     0,     0,     0,    29,     0,    82,     0,
+     0,     0,     0,     0,    98,    21,    19,     0,     0,    38,
+    39,    40,    41,    42,    43,    44,    45,    89,    20,    88,
+    90,    91,     0,    96,     0,     0,     0,    65,    35,     0,
+     0,     0,    66,     0,     0,     0,    69,     0,     0,    70,
+     0,     0,     0,    22,    83,     0,     0,    85,     0,    88,
+     0,     0,   100,   106,    12,    99,    33,    30,    31,     0,
+    29,     0,     0,     0,     0,     0,     0,     0,     0,    51,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,   109,
+   110,   111,   108,     0,     0,     0,     0,     0,    67,     0,
+    71,    74,    75,    77,    72,    73,    76,    78,    81,    80,
+    23,    24,    25,    26,     0,    84,     0,    87,   101,   102,
+   103,   104,   105,     0,     0,     0,    68,     0,    86,     0,
+    79,     0,     0
 };
 
 static const short yydefgoto[] = {     1,
-    41,   114,   115,   116,    43,    44,    76,    77
+    39,   110,   111,   112,    41,    42,    72,    73
 };
 
 static const short yypact[] = {-32768,
-   255,   -52,   -45,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-    27,-32768,-32768,    42,    67,    72,-32768,    94,-32768,    80,
-    43,    46,    47,    53,    62,    63,    65,-32768,    76,    77,
-    78,    81,    88,-32768,   724,    86,   121,-32768,-32768,   454,
--32768,    40,-32768,-32768,   845,-32768,   105,    95,    90,    95,
-    95,-32768,   454,   724,   724,   724,   724,-32768,-32768,   724,
-   724,   400,   454,   400,   454,   400,   724,   327,   724,   454,
-   454,-32768,-32768,-32768,   104,    96,   391,   454,-32768,-32768,
--32768,   562,   724,   724,   724,   724,   724,   724,   724,   724,
-   724,   454,   724,   724,   724,   724,-32768,-32768,    97,   160,
-   724,-32768,-32768,   104,   391,   445,   445,   445,   445,   894,
-   919,   -34,-32768,   104,-32768,   -26,   716,   -11,   145,    -8,
-   391,   163,     0,   748,-32768,    -2,   773,    -4,   164,   724,
--32768,-32768,    79,   130,  1120,   496,   496,    70,    70,    70,
-    70,    70,    70,    79,-32768,    79,    34,    34,   320,-32768,
-   178,    95,   868,-32768,-32768,   180,   400,   724,-32768,   400,
-   454,   454,-32768,   454,   454,-32768,   508,   454,   400,   454,
-   454,-32768,-32768,   724,   454,-32768,   454,    79,   616,   670,
-   -17,-32768,-32768,-32768,-32768,   136,   445,    31,   801,   -44,
-   944,   -42,   969,   -37,   994,   -31,  1019,   110,   111,   391,
-    -3,    -6,   -24,  1044,    36,  1069,   826,   112,   175,-32768,
-   445,-32768,   445,   724,   724,   724,   724,   724,-32768,   724,
+   218,   -41,   -44,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+    27,-32768,-32768,     8,    34,    40,-32768,    58,-32768,    59,
+     1,     2,    24,    25,    37,-32768,    38,    48,    49,    53,
+    54,   746,    15,    44,-32768,-32768,-32768,   426,-32768,    35,
+-32768,-32768,  1008,-32768,   104,    21,    46,    21,    21,-32768,
+   426,   746,   746,   746,   746,-32768,-32768,   746,   746,   361,
+   426,   361,   746,   289,   746,   426,   426,-32768,-32768,-32768,
+    69,    39,  1048,   426,-32768,-32768,   556,   746,   746,   746,
+   746,   746,   746,   746,   746,   746,   426,   746,   746,   746,
+   746,-32768,-32768,-32768,    68,   130,   746,-32768,-32768,    69,
+  1048,  1063,  1063,  1063,  1063,   680,   740,   -20,-32768,    69,
+-32768,   -30,    80,    -4,   773,   -12,  1048,   800,-32768,   -27,
+   419,    -5,   134,   746,-32768,-32768,   137,   100,  1033,   131,
+   131,    57,    57,    57,    57,    57,    57,   137,-32768,   137,
+     3,     3,   353,-32768,   146,    21,   613,-32768,-32768,   149,
+   361,   746,-32768,   361,   426,   426,-32768,   426,   426,-32768,
+   491,   426,   426,-32768,-32768,   746,   426,-32768,   426,   137,
+   621,   686,   136,-32768,-32768,-32768,-32768,   110,  1063,   -25,
+   484,   -57,   826,   -37,   852,   -36,   878,   -35,   904,    89,
+    90,  1048,   -34,   930,   -33,   956,   549,    93,    -3,-32768,
+  1063,-32768,  1063,   746,   746,   746,   746,   746,-32768,   746,
 -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-   454,-32768,   454,-32768,-32768,-32768,-32768,-32768,   400,-32768,
-   454,   445,   445,   445,   445,   445,  1094,   115,   116,    10,
-   118,-32768,-32768,-32768,   454,-32768,   119,-32768,   195,-32768
+-32768,-32768,-32768,-32768,   361,-32768,   426,-32768,  1063,  1063,
+  1063,  1063,  1063,   982,     0,    94,-32768,   426,-32768,    99,
+-32768,   181,-32768
 };
 
 static const short yypgoto[] = {-32768,
--32768,    75,  -159,   -50,-32768,   -47,   -59,    -1
+-32768,   108,  -147,   -59,-32768,   -42,   -55,    -1
 };
 
 
-#define	YYLAST		1185
-
-
-static const short yytable[] = {    45,
-   100,   161,   102,   103,   167,   122,   233,   199,   175,   231,
-   128,   129,   169,   120,   156,   123,    78,   126,    78,    46,
-   157,   158,   255,    78,   214,   215,   216,   217,   218,    78,
-   221,    47,   223,    72,    48,   162,    78,   225,   157,   158,
-   157,   158,    47,   227,   157,   158,   157,   158,   159,    78,
-   235,   105,   106,   107,   108,   109,   157,   158,   110,   111,
-   117,   119,   121,   163,   121,   124,   121,   127,   234,    49,
-   176,   232,   173,   249,    50,    42,   133,   157,   158,    51,
-   135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
-   146,   147,   148,   149,   150,   257,    78,    95,    96,   153,
-    78,     6,    52,     7,   183,   219,   186,    99,   201,   188,
-   237,    79,    80,    73,    75,   208,    60,   209,   202,    61,
-    62,    53,    54,    55,    56,    57,    63,   104,   178,    91,
-   130,    93,    94,    95,    96,    64,    65,   118,    66,    75,
-    93,    94,    95,    96,    75,    75,    58,    59,    74,    67,
-    68,    69,   132,   101,    70,   121,   187,   164,   189,   191,
-   193,    71,   195,   197,    78,   200,   145,   121,   204,   206,
-   131,   248,   207,   151,   152,   168,   177,   211,   213,   179,
-   182,   251,   185,   158,   229,   230,   240,   241,   250,   253,
-   254,   165,   256,   258,   260,    82,    83,    84,    85,    86,
-    87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
-     0,     0,   242,   243,   244,   245,   246,     0,   247,   166,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   200,     0,     0,     0,   190,   192,   121,   194,   196,
-     0,     0,    75,     0,   203,   205,     0,     0,     0,    75,
-     0,    75,     0,   200,   259,     2,     0,     3,     4,     5,
-     0,     6,     0,     7,     8,     9,    10,     0,    11,     0,
-    12,    13,     0,     0,     0,    14,    15,    16,     0,    17,
-    18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    29,    30,    31,    32,    33,     0,     0,     0,     0,
-     0,    34,     0,     0,     0,    75,     0,     0,     0,     0,
-     0,     0,     0,     0,    35,    75,     0,     0,     0,     0,
-     0,    36,    37,     0,     0,     0,    38,    39,    40,   112,
-     4,     5,   113,     6,     0,     7,     8,     9,    10,     0,
-     0,     0,    12,    13,     0,     0,     0,    14,     0,     0,
-     0,    17,     0,     0,    20,    21,    22,    23,    24,    25,
-    26,    27,    28,    29,    30,    31,    32,    33,     0,     0,
-    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
-   130,    93,    94,    95,    96,     0,    35,     0,     0,     0,
-     0,     0,     0,    36,    37,   181,     0,     0,     0,     0,
-    40,   125,   112,     4,     5,   113,     6,     0,     7,     8,
-     9,    10,     0,     0,     0,    12,    13,     0,     0,     0,
-    14,     0,     0,     0,    17,     0,     0,    20,    21,    22,
-    23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-    33,    82,    83,    84,    85,    86,    87,    88,    89,    90,
-    91,    92,    93,    94,    95,    96,     3,     4,     5,    35,
-     6,     0,     7,     8,     9,    10,    36,    37,     0,    12,
-    13,     0,     0,    40,    14,     0,     0,     0,    17,     0,
-     0,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-    29,    30,    31,    32,    33,    82,    83,    84,    85,    86,
-    87,    88,    89,    90,    91,   130,    93,    94,    95,    96,
-     3,     4,     5,    35,     6,     0,     7,     8,     9,    10,
-    36,    37,     0,    12,    13,     0,     0,    40,    14,     0,
-     0,     0,   198,     0,     0,    20,    21,    22,    23,    24,
-    25,    26,    27,    28,    29,    30,    31,    32,    33,    85,
-    86,    87,    88,    89,    90,    91,   130,    93,    94,    95,
-    96,     0,     0,     0,     3,     4,   134,    35,     6,     0,
-     7,     8,     9,    10,    36,    37,     0,    12,    13,     0,
-     0,    40,    14,     0,     0,     0,    17,     0,     0,    20,
-    21,    22,    23,    24,    25,    26,    27,    28,     0,    30,
-    31,    32,    33,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     3,     4,
-   210,    35,     6,     0,     7,     8,     9,    10,    36,    37,
-     0,    12,    13,     0,     0,    40,    14,     0,     0,     0,
+#define	YYLAST		1126
+
+
+static const short yytable[] = {    43,
+   161,    74,   116,    96,   120,    98,    99,   167,   155,   227,
+   122,   123,   238,   191,   151,   152,   211,   151,   152,   151,
+   152,    74,    74,    74,    74,    74,   150,     6,    44,     7,
+    68,    45,   151,   152,    46,    47,   213,   215,   217,   221,
+   223,    48,    69,   153,   151,   152,   165,    49,   209,   101,
+   102,   103,   104,   105,    74,    45,   106,   107,   113,   115,
+   117,   118,   117,   121,    90,    91,    50,   156,   168,   157,
+   228,    70,   127,    58,    59,   129,   130,   131,   132,   133,
+   134,   135,   136,   137,   138,   140,   141,   142,   143,   144,
+   240,   178,   154,    74,   180,   147,    60,    61,    51,    52,
+    53,    54,    55,   175,    75,    76,    95,    97,    40,    62,
+    63,   198,   125,   199,    86,   124,    88,    89,    90,    91,
+    64,    65,   170,    56,    57,    66,    67,    74,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+    89,    90,    91,   145,   146,    71,   169,   171,   174,   117,
+   179,   177,   181,   183,   185,   152,   187,   189,   100,   192,
+   194,   196,   219,   220,   197,   235,   226,   239,   114,   201,
+   203,   236,   241,    71,    71,   204,   205,   206,   207,   208,
+   243,   126,    80,    81,    82,    83,    84,    85,    86,   124,
+    88,    89,    90,    91,   139,     0,    88,    89,    90,    91,
+     0,     0,   229,   230,   231,   232,   233,     0,   234,     0,
+     0,     0,     0,     0,     0,     0,     0,   242,     2,     0,
+     3,     4,     5,   117,     6,     0,     7,     8,     9,    10,
+     0,    11,     0,    12,    13,     0,   192,     0,    14,    15,
+    16,     0,    17,    18,    19,    20,    21,    22,    23,    24,
+    25,    26,    27,    28,    29,    30,    31,     0,     0,     0,
+     0,     0,   182,   184,     0,   186,   188,     0,     0,   193,
+   195,     0,     0,     0,    71,    32,    71,     0,     0,     0,
+     0,     0,    33,    34,     0,     0,     0,    35,    36,    37,
+    38,   108,     4,     5,   109,     6,     0,     7,     8,     9,
+    10,     0,     0,     0,    12,    13,     0,     0,     0,    14,
+     0,     0,     0,    17,     0,     0,    20,    21,    22,    23,
+    24,    25,    26,    27,    28,    29,    30,    31,     0,     0,
+     0,     0,     0,     0,    71,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,    32,     0,     0,     0,
+     0,     0,     0,    33,    34,     0,     0,     0,     0,     0,
+     0,    38,   119,   108,     4,     5,   109,     6,     0,     7,
+     8,     9,    10,     0,     0,     0,    12,    13,     0,     0,
+     0,    14,     0,     0,     0,    17,     0,     0,    20,    21,
+    22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+     0,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+    86,   124,    88,    89,    90,    91,     0,     0,    32,     0,
+     0,     0,     0,     0,     0,    33,    34,   173,     3,     4,
+     5,   166,     6,    38,     7,     8,     9,    10,     0,     0,
+     0,    12,    13,     0,     0,     0,    14,     0,     0,     0,
     17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
-    27,    28,     0,    30,    31,    32,    33,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     3,     4,   212,    35,     6,     0,     7,     8,
-     9,    10,    36,    37,     0,    12,    13,     0,     0,    40,
-    14,     0,     0,     0,    17,     0,     0,    20,    21,    22,
-    23,    24,    25,    26,    27,    28,     0,    30,    31,    32,
-    33,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     3,     4,   160,    35,
-     6,     0,     7,     8,     9,    10,    36,    37,     0,    12,
-    13,     0,     0,    40,    14,     0,     0,     0,    17,     0,
-     0,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-   170,    30,    31,    32,    33,     0,    82,    83,    84,    85,
-    86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
-    96,     0,     0,    35,     0,   174,     0,     0,     0,     0,
-    36,    37,     0,     0,   171,     0,     0,    40,    82,    83,
-    84,    85,    86,    87,    88,    89,    90,    91,   130,    93,
-    94,    95,    96,   220,     0,     0,     0,     0,     0,     0,
-     0,     0,   172,    82,    83,    84,    85,    86,    87,    88,
-    89,    90,    91,   130,    93,    94,    95,    96,   239,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,    82,    83,    84,    85,    86,    87,    88,    89,    90,
-    91,    92,    93,    94,    95,    96,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,    82,    83,    84,    85,
-    86,    87,    88,    89,    90,    91,   130,    93,    94,    95,
-    96,    81,     0,     0,     0,    82,    83,    84,    85,    86,
-    87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
-     0,     0,     0,     0,     0,     0,    97,    98,    82,    83,
-    84,    85,    86,    87,    88,    89,    90,    91,   130,    93,
-    94,    95,    96,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   184,    82,    83,    84,    85,    86,    87,
-    88,    89,    90,    91,   130,    93,    94,    95,    96,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,   154,    82,
-    83,    84,    85,    86,    87,    88,    89,    90,    91,   130,
-    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   155,    82,    83,    84,    85,    86,    87,
-    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,   222,    82,
-    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
-    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   224,    82,    83,    84,    85,    86,    87,
-    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,   226,    82,
-    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
-    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   228,    82,    83,    84,    85,    86,    87,
-    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,   236,    82,
-    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
-    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,   238,    82,    83,    84,    85,    86,    87,
-    88,    89,    90,    91,   130,    93,    94,    95,    96,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,   252,   180,
-    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
-   130,    93,    94,    95,    96
+    27,    28,    29,    30,    31,     0,     0,    77,    78,    79,
+    80,    81,    82,    83,    84,    85,    86,   124,    88,    89,
+    90,    91,     0,    32,     0,     0,     0,     0,     0,     0,
+    33,    34,     0,     3,     4,     5,   210,     6,    38,     7,
+     8,     9,    10,     0,     0,     0,    12,    13,     0,     0,
+     0,    14,     0,     0,     0,   190,     0,     0,    20,    21,
+    22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+     0,     0,    77,    78,    79,    80,    81,    82,    83,    84,
+    85,    86,    87,    88,    89,    90,    91,     0,    32,     0,
+     0,     0,     0,     0,     0,    33,    34,     0,     3,     4,
+   128,   225,     6,    38,     7,     8,     9,    10,     0,     0,
+     0,    12,    13,     0,     0,     0,    14,     0,     0,     0,
+    17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
+     0,    28,    29,    30,    31,     0,     0,    77,    78,    79,
+    80,    81,    82,    83,    84,    85,    86,   124,    88,    89,
+    90,    91,     0,    32,     0,     0,     0,     0,     0,     0,
+    33,    34,     0,     3,     4,   200,     0,     6,    38,     7,
+     8,     9,    10,     0,     0,     0,    12,    13,     0,     0,
+     0,    14,     0,     0,     0,    17,     0,     0,    20,    21,
+    22,    23,    24,    25,    26,     0,    28,    29,    30,    31,
+     0,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+    86,   124,    88,    89,    90,    91,     0,     0,    32,     0,
+     0,     0,     0,     0,     0,    33,    34,   176,     3,     4,
+   202,     0,     6,    38,     7,     8,     9,    10,     0,     0,
+     0,    12,    13,     0,     0,     0,    14,     0,     0,     0,
+    17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
+     0,    28,    29,    30,    31,     0,     0,     0,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,   124,    88,
+    89,    90,    91,    32,     0,     0,     0,     0,     3,     4,
+    33,    34,     6,   148,     7,     8,     9,    10,    38,     0,
+     0,    12,    13,     0,     0,     0,    14,     0,     0,     0,
+    17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
+     0,    28,    29,    30,    31,   158,     0,     0,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,   124,    88,
+    89,    90,    91,    32,     0,     0,     0,     0,     0,     0,
+    33,    34,   162,   149,     0,     0,     0,     0,    38,     0,
+     0,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+    86,    87,    88,    89,    90,    91,     0,     0,     0,     0,
+     0,     0,     0,     0,   159,     0,   160,     0,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,   124,    88,
+    89,    90,    91,     0,     0,     0,     0,     0,     0,     0,
+     0,   163,     0,   164,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,   212,
+    77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+    87,    88,    89,    90,    91,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,   214,    77,    78,    79,    80,
+    81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+    91,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   216,    77,    78,    79,    80,    81,    82,    83,    84,
+    85,    86,    87,    88,    89,    90,    91,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,   218,    77,    78,
+    79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
+    89,    90,    91,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   222,    77,    78,    79,    80,    81,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,   224,
+    77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+   124,    88,    89,    90,    91,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,   237,    77,    78,    79,    80,
+    81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+    91,     0,     0,     0,     0,     0,     0,    92,    93,    94,
+   172,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+    86,   124,    88,    89,    90,    91,    77,    78,    79,    80,
+    81,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+    91,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+    86,   124,    88,    89,    90,    91
 };
 
 static const short yycheck[] = {     1,
-    48,    13,    50,    51,    13,    65,    13,   167,    13,    13,
-    70,    71,    13,    64,    49,    66,    61,    68,    61,    72,
-    47,    48,    13,    61,    42,    43,    44,    45,    46,    61,
-    75,    77,    75,    35,     8,    47,    61,    75,    47,    48,
-    47,    48,    77,    75,    47,    48,    47,    48,    75,    61,
-    75,    53,    54,    55,    56,    57,    47,    48,    60,    61,
-    62,    63,    64,    75,    66,    67,    68,    69,    75,    28,
-    75,    75,    75,   233,     8,     1,    78,    47,    48,     8,
+    13,    59,    62,    46,    64,    48,    49,    13,    13,    13,
+    66,    67,    13,   161,    45,    46,    74,    45,    46,    45,
+    46,    59,    59,    59,    59,    59,    47,     7,    70,     9,
+    32,    76,    45,    46,     8,    28,    74,    74,    74,    74,
+    74,     8,    28,    74,    45,    46,    74,     8,    74,    51,
+    52,    53,    54,    55,    59,    76,    58,    59,    60,    61,
+    62,    63,    64,    65,    62,    63,     9,    72,    74,    74,
+    74,    28,    74,    73,    73,    77,    78,    79,    80,    81,
     82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
-    92,    93,    94,    95,    96,   255,    61,    64,    65,   101,
-    61,     7,     9,     9,   152,    75,   157,     3,   168,   160,
-    75,    72,    73,    28,    40,   175,    74,   177,   169,    74,
-    74,    42,    43,    44,    45,    46,    74,    53,   130,    60,
-    61,    62,    63,    64,    65,    74,    74,    63,    74,    65,
-    62,    63,    64,    65,    70,    71,    67,    68,    28,    74,
-    74,    74,    78,    64,    74,   157,   158,    13,   160,   161,
-   162,    74,   164,   165,    61,   167,    92,   169,   170,   171,
-    75,   231,   174,    77,    15,    13,    13,   179,   180,    50,
-     3,   241,     3,    48,    75,    75,    75,    13,   239,    75,
-    75,    47,    75,    75,     0,    51,    52,    53,    54,    55,
-    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
-    -1,    -1,   214,   215,   216,   217,   218,    -1,   220,    75,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,   233,    -1,    -1,    -1,   161,   162,   239,   164,   165,
-    -1,    -1,   168,    -1,   170,   171,    -1,    -1,    -1,   175,
-    -1,   177,    -1,   255,     0,     1,    -1,     3,     4,     5,
-    -1,     7,    -1,     9,    10,    11,    12,    -1,    14,    -1,
-    16,    17,    -1,    -1,    -1,    21,    22,    23,    -1,    25,
-    26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-    36,    37,    38,    39,    40,    41,    -1,    -1,    -1,    -1,
-    -1,    47,    -1,    -1,    -1,   231,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    60,   241,    -1,    -1,    -1,    -1,
-    -1,    67,    68,    -1,    -1,    -1,    72,    73,    74,     3,
-     4,     5,     6,     7,    -1,     9,    10,    11,    12,    -1,
-    -1,    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,
-    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,    33,
-    34,    35,    36,    37,    38,    39,    40,    41,    -1,    -1,
+   238,   151,    13,    59,   154,    97,    73,    73,    40,    41,
+    42,    43,    44,   146,    70,    71,     3,    62,     1,    73,
+    73,   167,    74,   169,    58,    59,    60,    61,    62,    63,
+    73,    73,   124,    65,    66,    73,    73,    59,    49,    50,
     51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
-    61,    62,    63,    64,    65,    -1,    60,    -1,    -1,    -1,
-    -1,    -1,    -1,    67,    68,    76,    -1,    -1,    -1,    -1,
-    74,    75,     3,     4,     5,     6,     7,    -1,     9,    10,
-    11,    12,    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,
-    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,    30,
-    31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
-    41,    51,    52,    53,    54,    55,    56,    57,    58,    59,
-    60,    61,    62,    63,    64,    65,     3,     4,     5,    60,
-     7,    -1,     9,    10,    11,    12,    67,    68,    -1,    16,
-    17,    -1,    -1,    74,    21,    -1,    -1,    -1,    25,    -1,
-    -1,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-    37,    38,    39,    40,    41,    51,    52,    53,    54,    55,
-    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
-     3,     4,     5,    60,     7,    -1,     9,    10,    11,    12,
-    67,    68,    -1,    16,    17,    -1,    -1,    74,    21,    -1,
-    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,
-    33,    34,    35,    36,    37,    38,    39,    40,    41,    54,
-    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-    65,    -1,    -1,    -1,     3,     4,     5,    60,     7,    -1,
-     9,    10,    11,    12,    67,    68,    -1,    16,    17,    -1,
-    -1,    74,    21,    -1,    -1,    -1,    25,    -1,    -1,    28,
-    29,    30,    31,    32,    33,    34,    35,    36,    -1,    38,
-    39,    40,    41,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,
-     5,    60,     7,    -1,     9,    10,    11,    12,    67,    68,
-    -1,    16,    17,    -1,    -1,    74,    21,    -1,    -1,    -1,
+    61,    62,    63,    76,    15,    38,    13,    48,     3,   151,
+   152,     3,   154,   155,   156,    46,   158,   159,    51,   161,
+   162,   163,    74,    74,   166,   225,    74,    74,    61,   171,
+   172,   227,    74,    66,    67,    40,    41,    42,    43,    44,
+     0,    74,    52,    53,    54,    55,    56,    57,    58,    59,
+    60,    61,    62,    63,    87,    -1,    60,    61,    62,    63,
+    -1,    -1,   204,   205,   206,   207,   208,    -1,   210,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,     0,     1,    -1,
+     3,     4,     5,   225,     7,    -1,     9,    10,    11,    12,
+    -1,    14,    -1,    16,    17,    -1,   238,    -1,    21,    22,
+    23,    -1,    25,    26,    27,    28,    29,    30,    31,    32,
+    33,    34,    35,    36,    37,    38,    39,    -1,    -1,    -1,
+    -1,    -1,   155,   156,    -1,   158,   159,    -1,    -1,   162,
+   163,    -1,    -1,    -1,   167,    58,   169,    -1,    -1,    -1,
+    -1,    -1,    65,    66,    -1,    -1,    -1,    70,    71,    72,
+    73,     3,     4,     5,     6,     7,    -1,     9,    10,    11,
+    12,    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,    21,
+    -1,    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,
+    32,    33,    34,    35,    36,    37,    38,    39,    -1,    -1,
+    -1,    -1,    -1,    -1,   227,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,
+    -1,    -1,    -1,    65,    66,    -1,    -1,    -1,    -1,    -1,
+    -1,    73,    74,     3,     4,     5,     6,     7,    -1,     9,
+    10,    11,    12,    -1,    -1,    -1,    16,    17,    -1,    -1,
+    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,
+    30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+    -1,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63,    -1,    -1,    58,    -1,
+    -1,    -1,    -1,    -1,    -1,    65,    66,    75,     3,     4,
+     5,    13,     7,    73,     9,    10,    11,    12,    -1,    -1,
+    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,    -1,
     25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
-    35,    36,    -1,    38,    39,    40,    41,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,     3,     4,     5,    60,     7,    -1,     9,    10,
-    11,    12,    67,    68,    -1,    16,    17,    -1,    -1,    74,
-    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,    30,
-    31,    32,    33,    34,    35,    36,    -1,    38,    39,    40,
-    41,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,    13,    60,
-     7,    -1,     9,    10,    11,    12,    67,    68,    -1,    16,
-    17,    -1,    -1,    74,    21,    -1,    -1,    -1,    25,    -1,
-    -1,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-    13,    38,    39,    40,    41,    -1,    51,    52,    53,    54,
-    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-    65,    -1,    -1,    60,    -1,    13,    -1,    -1,    -1,    -1,
-    67,    68,    -1,    -1,    47,    -1,    -1,    74,    51,    52,
-    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
-    63,    64,    65,    13,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    75,    51,    52,    53,    54,    55,    56,    57,
-    58,    59,    60,    61,    62,    63,    64,    65,    13,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
-    60,    61,    62,    63,    64,    65,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    51,    52,    53,    54,
-    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-    65,    47,    -1,    -1,    -1,    51,    52,    53,    54,    55,
-    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
-    -1,    -1,    -1,    -1,    -1,    -1,    72,    73,    51,    52,
-    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
-    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    76,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    35,    36,    37,    38,    39,    -1,    -1,    49,    50,    51,
     52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
-    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
-    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    62,    63,    -1,    58,    -1,    -1,    -1,    -1,    -1,    -1,
+    65,    66,    -1,     3,     4,     5,    13,     7,    73,     9,
+    10,    11,    12,    -1,    -1,    -1,    16,    17,    -1,    -1,
+    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,
+    30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+    -1,    -1,    49,    50,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    -1,    58,    -1,
+    -1,    -1,    -1,    -1,    -1,    65,    66,    -1,     3,     4,
+     5,    13,     7,    73,     9,    10,    11,    12,    -1,    -1,
+    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,    -1,
+    25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
+    -1,    36,    37,    38,    39,    -1,    -1,    49,    50,    51,
     52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    50,
+    62,    63,    -1,    58,    -1,    -1,    -1,    -1,    -1,    -1,
+    65,    66,    -1,     3,     4,     5,    -1,     7,    73,     9,
+    10,    11,    12,    -1,    -1,    -1,    16,    17,    -1,    -1,
+    -1,    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,
+    30,    31,    32,    33,    34,    -1,    36,    37,    38,    39,
+    -1,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63,    -1,    -1,    58,    -1,
+    -1,    -1,    -1,    -1,    -1,    65,    66,    75,     3,     4,
+     5,    -1,     7,    73,     9,    10,    11,    12,    -1,    -1,
+    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,    -1,
+    25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
+    -1,    36,    37,    38,    39,    -1,    -1,    -1,    49,    50,
+    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+    61,    62,    63,    58,    -1,    -1,    -1,    -1,     3,     4,
+    65,    66,     7,    74,     9,    10,    11,    12,    73,    -1,
+    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,    -1,
+    25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
+    -1,    36,    37,    38,    39,    13,    -1,    -1,    49,    50,
+    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+    61,    62,    63,    58,    -1,    -1,    -1,    -1,    -1,    -1,
+    65,    66,    13,    74,    -1,    -1,    -1,    -1,    73,    -1,
+    -1,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    72,    -1,    74,    -1,    49,    50,
     51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
-    61,    62,    63,    64,    65
+    61,    62,    63,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    72,    -1,    74,    49,    50,    51,    52,    53,    54,
+    55,    56,    57,    58,    59,    60,    61,    62,    63,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    74,
+    49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+    59,    60,    61,    62,    63,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    74,    49,    50,    51,    52,
+    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+    63,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    74,    49,    50,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    74,    49,    50,
+    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+    61,    62,    63,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    74,    49,    50,    51,    52,    53,    54,
+    55,    56,    57,    58,    59,    60,    61,    62,    63,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    74,
+    49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+    59,    60,    61,    62,    63,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    74,    49,    50,    51,    52,
+    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+    63,    -1,    -1,    -1,    -1,    -1,    -1,    70,    71,    72,
+    48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63,    49,    50,    51,    52,
+    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+    63,    49,    50,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
 
@@ -998,7 +982,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
@@ -1292,10 +1276,10 @@ case 30:
 {push(&yyval, &yyvsp[0]);yyval.type = ARR;;
     break;}
 case 31:
-{exec_clause(&yyval);yyval.type = ARR;;
+{exec_clause(&yyval);;
     break;}
 case 32:
-{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;;
+{range_array(&yyval, yyvsp[0].text);;
     break;}
 case 33:
 {if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = PushArray((double*)malloc((int)(yyvsp[0].val-yyvsp[-2].val+2)*sizeof(double)))))
@@ -1337,9 +1321,6 @@ case 45:
 case 50:
 {yyval.val = yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 51:
-{yyval.type = ARR;;
-    break;}
 case 52:
 {yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
     break;}
@@ -1426,130 +1407,127 @@ case 78:
 {yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 79:
-{range_array2(&yyvsp[-3], &yyvsp[-1]);yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)) : 0.0; yyval.type = NUM;;
+{proc_clause(&yyvsp[-3]); yyval.val=yyvsp[-9].tptr->fnctptr ? (*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;;
     break;}
 case 80:
-{range_array2(&yyvsp[-5], &yyvsp[-3]); yyval.val = yyvsp[-7].tptr->fnctptr ? ((*yyvsp[-7].tptr->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
     break;}
 case 81:
-{yyval.val= yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L)) : 0.0;;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
     break;}
 case 82:
-{yyval.val=yyvsp[-7].tptr->fnctptr ? ((*yyvsp[-7].tptr->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;;
+{if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
     break;}
 case 83:
-{proc_clause(&yyvsp[-3]); yyval.val=yyvsp[-9].tptr->fnctptr ? (*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;;
+{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
     break;}
 case 84:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
+{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
     break;}
 case 85:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
+{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);;
     break;}
 case 86:
-{if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
+{if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
     break;}
 case 87:
-{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
+{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);;
     break;}
 case 88:
-{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
-    break;}
-case 89:
-{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);;
-    break;}
-case 90:
-{if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
-    break;}
-case 91:
 {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 92:
+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 93:
+case 90:
 {yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 94:
+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 95:
+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 96:
+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 97:
+case 94:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
     break;}
-case 98:
+case 95:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
     break;}
-case 99:
+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 100:
+case 97:
 {yyval.val = -yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 101:
+case 98:
 {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
     break;}
-case 102:
+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 103:
+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 104:
-{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;
+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; 
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 105:
+case 102:
 {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;
+				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] += yyvsp[0].val;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 106:
+case 103:
 {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;
+				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= yyvsp[0].val;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 107:
+case 104:
 {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;
+				{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= yyvsp[0].val;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 108:
+case 105:
 {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ 
-				if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= yyvsp[0].val;
+				if(yyvsp[0].val != 0.0) {yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= yyvsp[0].val;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 109:
+case 106:
 {make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
     break;}
-case 110:
+case 107:
 {make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
     break;}
-case 111:
+case 108:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 112:
+case 109:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 113:
+case 110:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 114:
+case 111:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
 }
@@ -1776,7 +1754,276 @@ yyerrhandle:
 }
 
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Cache spreadsheet data for repeated access
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SsRangeData {
+typedef struct _rng_data {
+	_rng_data *next;
+	unsigned int h1, h2;
+	RECT rec;
+	double *vals;
+	char *name;
+	int nvals;
+	double dSum, dMean, dQuart1, dQuart2, dQuart3;
+	bool bSum, bMean, bQuart1, bQuart2, bQuart3;
+	}rng_data;
+
+public:
+	SsRangeData();
+	~SsRangeData();
+	void Clear();
+	bool GetData(char *rng_desc,  double **vals, int *nvals, char **name);
+	void rmData(double *vals, int nvals);
+	void cellModified(int row, int col);
+	double sum(double *vals, int nvals);
+	double mean(double *vals, int nvals);
+	double quartile1(double *vals, int nvals);
+	double quartile2(double *vals, int nvals);
+	double quartile3(double *vals, int nvals);
+
+private:
+	rng_data *RngData;
+
+	bool FindData(unsigned int h1, unsigned int h2, rng_data **rda);
+	bool FindData(double *vals, int nvals, rng_data **rda);
+	bool SetArray(rng_data *rda, char *range);
+	void do_quartiles(rng_data *rda);
+}; 
+ 
+SsRangeData::SsRangeData()
+{
+	RngData = 0L;
+} 
+
+SsRangeData::~SsRangeData()
+{
+	Clear();
+}
+
+void
+SsRangeData::Clear()
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		nxt = RngData->next;
+		if(RngData->vals) free(RngData->vals);
+		if(RngData->name) free(RngData->name);
+		free(RngData); 		RngData = nxt;
+		}
+}
+
+bool
+SsRangeData::FindData(unsigned int h1, unsigned int h2, rng_data **rda)
+{ 
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(nxt->h1 == h1 && nxt->h2 == h2) {
+			*rda = nxt; 	return true;
+			}
+		nxt = nxt->next;
+		}
+	return false;
+}
+
+bool
+SsRangeData::FindData(double *vals, int nvals, rng_data **rda)
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(nxt->vals == vals && nxt->nvals == nvals) {
+			*rda = nxt;	return true;
+			}
+		nxt = nxt->next;
+		}
+	return false;
+}
+
+bool
+SsRangeData::SetArray(rng_data *rda, char *range)
+{ 
+	AccRange *r;
+	int row, col;
+	anyResult ares;
+
+	if(!range || !range[0] || !(r = new AccRange(range))) return false;
+	if(!r->GetFirst(&col, &row) || !(rda->vals =  (double*)malloc(r->CountItems() * sizeof(double)))) {
+		delete(r); 		return false;
+		} 
+	r->BoundRec(&rda->rec);
+	parse_level++;			r->GetFirst(&col, &row);
+	for(rda->nvals = 0; r->GetNext(&col, &row); ) {
+		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
+			switch(ares.type) {
+			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
+				rda->vals[rda->nvals++] = ares.value;
+				break;
+				}
+			}
+		}
+	rda->name = (char*)memdup(range, (int)strlen(range)+1, 0);
+	parse_level--;
+	delete(r);
+	return true;
+}
+
+void
+SsRangeData::rmData(double *vals, int nvals)
+{
+	rng_data *rda, *rmrda;
+
+	if(!FindData(vals, nvals, &rmrda)) return;
+	if(rmrda == RngData) RngData = RngData->next;
+	else {
+		rda = RngData;
+		while(rda->next && rda->next != rmrda) rda = rda->next;
+		if(rda->next == rmrda) rda->next = rmrda->next;
+		else return;
+		}
+	rda = RngData;
+	while(rda) {
+		if(((rda->rec.top <= rmrda->rec.top && rda->rec.bottom >= rmrda->rec.top)
+			|| (rda->rec.top <= rmrda->rec.bottom && rda->rec.top >= rmrda->rec.top))
+			&&((rda->rec.left <= rmrda->rec.left && rda->rec.right >= rmrda->rec.left)
+			|| (rda->rec.left <= rmrda->rec.right && rda->rec.left >= rmrda->rec.left))){
+			rmData(rda->vals, rda->nvals);
+			rda = RngData;
+			}
+		else rda = rda->next;
+		}
+	if(rmrda->vals) free(rmrda->vals);
+	if(rmrda->name) free(rmrda->name);
+	free(rmrda);
+}
+
+void
+SsRangeData::cellModified(int row, int col)
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(col >= nxt->rec.left && col <= nxt->rec.right && row >= nxt->rec.top && col <= nxt->rec.bottom){
+			rmData(nxt->vals, nxt->nvals);
+			nxt = RngData;
+			}
+		else nxt = nxt->next;
+		}
+	return;
+}
+
+void
+SsRangeData::do_quartiles(rng_data *rda)
+{
+	double *vals;
+
+	if(rda->vals && rda->nvals && (vals = (double*)memdup(rda->vals, rda->nvals*sizeof(double), 0))){
+		d_quartile(rda->nvals, vals, &rda->dQuart1, &rda->dQuart2, &rda->dQuart3);
+		free(vals);
+		}
+	rda->bQuart1 = rda->bQuart2 = rda->bQuart3 = true;
+}
+
+bool  
+SsRangeData::GetData(char *rng_desc, double **vals, int *nvals, char **name)
+{ 
+	rng_data *rda;
+	unsigned int h1, h2;
+
+	h1 = HashValue((unsigned char*) rng_desc);
+	h2 = Hash2((unsigned char*) rng_desc);
+	if(FindData(h1, h2, &rda)) {
+		*vals = rda->vals;	*nvals = rda->nvals;
+		if(name) *name = rda->name;
+		return true;
+		}
+	if(!(rda = (rng_data*) calloc(1, sizeof(rng_data))))return false;
+	SetArray(rda, rng_desc);
+	*vals = rda->vals; 		*nvals = rda->nvals;
+	if(name) *name = rda->name;
+	rda->h1 = h1; 			rda->h2 = h2; 
+	rda->next = RngData;		RngData = rda;
+	return true;
+}
+
+double
+SsRangeData::sum(double *vals, int nvals)
+{
+	rng_data *rda;
+	int i;
+	double tmp;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bSum) return rda->dSum;
+		for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
+		rda->dSum = tmp;	rda->bSum = true;
+		return rda->dSum;
+		}
+	for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
+	return tmp;
+}
+
+double
+SsRangeData::mean(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bMean) return rda->dMean;
+		rda->dMean = d_amean(nvals, vals);
+		rda->bMean = true;
+		return rda->dMean;
+		}
+	return d_amean(nvals, vals);
+}
+
+double
+SsRangeData::quartile1(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart1) return rda->dQuart1;
+		do_quartiles(rda);	return rda->dQuart1;
+		}
+	return HUGE_VAL;
+}
+
+double
+SsRangeData::quartile2(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart2) return rda->dQuart2;
+		do_quartiles(rda);	return rda->dQuart2;
+		}
+	return HUGE_VAL;
+}
+
+double
+SsRangeData::quartile3(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart3) return rda->dQuart3;
+		do_quartiles(rda);	return rda->dQuart3;
+		}
+	return HUGE_VAL;
+}
+
+static SsRangeData RangeData;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // The symrec class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) 
 {
 	h_name = h_n;	h2_name = h2_n;		type = typ;
@@ -1788,8 +2035,8 @@ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt)
 
 symrec::~symrec()
 {
-	if(name) free(name);	name = 0L;
-	if(text) free(text);	text = 0L;
+	if(name) free(name);		name = 0L;
+	if(text) free(text);		text = 0L;
 }
 
 double
@@ -1816,6 +2063,7 @@ symrec::GetValue(void *re)
 	anyResult ares;
 	YYSTYPE *res = (YYSTYPE*)re;
 
+	if(!res) return;
 	if(isSSval) {
 		if(row < 0 && col < 0) InitSS();
 		res->a_data = 0L;	res->a_count = 0;
@@ -1855,13 +2103,12 @@ symrec::GetValue(void *re)
 		}
 	if(!isValid) NoInit();
 	if(a_data && a_count) {
-		if(text && text[0]) res->text = PushString(text);
-		else res->text = 0L;
-		res->a_data = a_data;	res->a_count = a_count;
-		res->val = 0.0;		res->type = ARR;
+		res->text = 0L;		res->a_count = a_count;
+		res->a_data = a_data;	res->val = 0.0;
+		res->type = ARR;
 		}
 	else if(text && text[0]) {
-		res->text = PushString(text);
+		res->text = text;
 		res->a_data = 0L;	res->a_count = 0;
 		res->val = 0.0;		res->type = STR;
 		}
@@ -1875,10 +2122,11 @@ symrec::GetValue(void *re)
 double 
 symrec::SetValue(double v)
 {
-	if(isSSval) {
+	if(isSSval && !bNoWrite) {
 		if(row < 0 && col < 0) InitSS();
 		if(curr_data->SetValue(row, col, v)){
 			if(curr_data) curr_data->Command(CMD_UPDATE, 0L, 0L);
+			RangeData.cellModified(row, col);
 			return var = v;
 			}
 		isSSval = false;
@@ -1895,11 +2143,12 @@ symrec::SetValue(void* d, void* s)
 	YYSTYPE *dest = (YYSTYPE*)d;
 	YYSTYPE *src = (YYSTYPE*)s;
 
-	if(isSSval && curr_data) {
+	if(isSSval && curr_data && !bNoWrite) {
 		if(row < 0 && col < 0) InitSS();
 		if(last_err_desc) curr_data->SetText(row, col, last_err_desc);
 		else if(src->type == STR) curr_data->SetText(row, col, src->text);
-		else if(src->type == ARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY");
+		else if(src->type == ARR || src->type == RANGEARR || (src->a_data)) 
+			curr_data->SetText(row, col, "#ARRAY");
 		else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text);
 		else {
 			if(curr_data->SetValue(row, col, src->val))
@@ -1909,14 +2158,17 @@ symrec::SetValue(void* d, void* s)
 				}
 			}
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
+		RangeData.cellModified(row, col);
 		}
-	isValid = true;
-	var = src->val;
-	if(text) free(text);		text = 0L;
-	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);
+	isValid = true;			var = src->val;
+	if(src->a_data && src->a_count) {
+		a_data = src->a_data;		a_count = src->a_count;
+		}
+	else if(src->text && src->text[0] && src->text != text) {
+		if(text) free(text);		text = 0L;
+		text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0);
+		}
+	if(d) GetValue(d);
 	return;
 }
 
@@ -1952,7 +2204,14 @@ symrec::NoInit()
 #endif
 	yywarn(message, true);
 }
-
+ 
+void LockData(bool lockExec, bool lockWrite) 
+{ 
+	RangeData.Clear();
+	bNoWrite = lockWrite;
+	bNoExec = lockExec;
+} 
+ 
 static void yyerror(char *s)
 {  
 	//called by yyparse on error
@@ -1962,11 +2221,35 @@ static void yyerror(char *s)
 
 static void yyargserr(char *s)
 {
-	//call from function on argument type/number mismatch
-	yyerror(s);
-	last_err_desc = "#ARGS";
+	//call from function on argument type mismatch
+	yyerror(s);	last_err_desc = "#ARGS";
+}
+
+static void yyargcnterr(char *s)
+{
+	//call from function on argument number mismatch
+	static char arg_cnt_err[80];
+	int cb;
+
+	cb = rlp_strcpy(arg_cnt_err, 80, "Wrong number of arguments\nin call to ");
+	cb += rlp_strcpy(arg_cnt_err+cb, 80-cb, s);
+	rlp_strcpy(arg_cnt_err+cb, 80-cb, ".");
+	yyargserr(arg_cnt_err);
 }
 
+static void yybadargerr(char *s)
+{
+	//call from function on argument number mismatch
+	static char bad_arg_err[80];
+	int cb;
+
+	cb = rlp_strcpy(bad_arg_err, 80, "Bad arguments in call to function\n");
+	cb += rlp_strcpy(bad_arg_err+cb, 80-cb, s);
+	rlp_strcpy(bad_arg_err+cb, 80-cb, ".");
+	yyargserr(bad_arg_err);
+}
+
+
 static char txt_tokenerr[80];
 static void yytokenerr(int c)
 {
@@ -2036,7 +2319,7 @@ static void store_res(YYSTYPE *res)
 		line_res.value = 0.0;
 		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
 		}
-	else if((res->type == ARR || (res->a_data)) && res->a_count == 1) {
+	else if((res->type == ARR || res->type == RANGEARR || (res->a_data)) && res->a_count == 1) {
 		line_res.type = ET_VALUE;
 		line_res.value = res->a_data[0];
 		}
@@ -2044,7 +2327,7 @@ static void store_res(YYSTYPE *res)
 		line_res.type = ET_VALUE;
 		line_res.value = res->val;
 		}
-	else if(res->type == ARR || (res->a_data)) {
+	else if(res->type == ARR || res->type == RANGEARR || (res->a_data)) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
 		line_res.a_data = res->a_data;
@@ -2133,6 +2416,7 @@ static int eval(YYSTYPE *dst, YYSTYPE *sr)
 	int s_buff_pos, s_yychar, s_yynerrs, length, parse_res;
 	anyResult *ar;
 
+	if(bNoExec) return 0;
 	if(!sr || !sr->text || !sr->text[0]) return 1;
 	s_buffer = buffer;		s_buff_pos = buff_pos;
 	s_yychar = yychar;		s_yynerrs = yynerrs;
@@ -2249,7 +2533,10 @@ static double sum(YYSTYPE *sr)
 	int i;
 
 	if(!sr) return 0.0;
-	if(sr->a_data){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.sum(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data){
 		for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i];
 		}
 	else sr->val = 0.0;
@@ -2259,9 +2546,13 @@ static double sum(YYSTYPE *sr)
 static double mean(YYSTYPE *sr) 
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.mean(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		sr->val = d_amean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -2271,6 +2562,7 @@ static double kurt(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count > 3){
 		sr->val = d_kurt(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -2280,6 +2572,7 @@ static double skew(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count > 2){
 		sr->val = d_skew(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -2295,6 +2588,7 @@ static double gmean(YYSTYPE *sr)
 			}
 		sr->val = d_gmean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -2310,33 +2604,46 @@ static double hmean(YYSTYPE *sr)
 			}
 		sr->val = d_hmean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile1(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile1(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile2(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile2(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile3(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile3(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -2377,7 +2684,7 @@ static double beta(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = betaf(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  beta(u, v).");
+	else yyargcnterr("beta(u, v)");
 	return sr->val;
 }
 
@@ -2388,7 +2695,7 @@ static double _gammp(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammp(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  gammp(a, x).");
+	else yyargcnterr("gammp(a, x)");
 	return sr->val;
 }
 
@@ -2399,7 +2706,7 @@ static double _gammq(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammq(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  gammq(a, x).");
+	else yyargcnterr("gammq(a, x)");
 	return sr->val;
 }
 
@@ -2414,7 +2721,7 @@ static double _betai(YYSTYPE *sr)
 			}
 		sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  betai(a, b, x).");
+	else yyargcnterr("betai(a, b, x)");
 	return sr->val;
 }
 
@@ -2425,7 +2732,7 @@ static double _bincof(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = bincof(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  bincof(n, k).");
+	else yyargcnterr("bincof(n, k)");
 	return sr->val;
 }
 
@@ -2436,7 +2743,7 @@ static double binomdist(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 3){
 		sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  binomdist(s, n, p).");
+	else yyargcnterr("binomdist(s, n, p)");
 	return sr->val;
 }
 
@@ -2449,7 +2756,7 @@ static double binomfreq(YYSTYPE *sr)
 		sr->val *= pow(sr->a_data[2], sr->a_data[0]);
 		sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  binomfreq(s, n, p).");
+	else yyargcnterr("binomfreq(s, n, p)");
 	return sr->val;
 }
 
@@ -2460,7 +2767,7 @@ static double normdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  normdist(x, mean, SD).");
+	else yyargcnterr("normdist(x, mean, SD)");
 	return sr->val;
 }
 
@@ -2471,7 +2778,7 @@ static double norminv(YYSTYPE *sr)
         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], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
+	else yyargcnterr("norminv(p, mean, SD)");
 	return sr->val;
 }
 
@@ -2482,7 +2789,7 @@ static double normfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  normfreq(x, mean, SD).");
+	else yyargcnterr("normfreq(x, mean, SD)");
 	return sr->val;
 }
 
@@ -2493,7 +2800,7 @@ static double expdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp_dist(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expdist(x, l).");
+	else yyargcnterr("expdist(x, l)");
 	return sr->val;
 }
 
@@ -2504,7 +2811,7 @@ static double expinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = exp_inv(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expinv(p, l).");
+	else yyargcnterr("expinv(p, l)");
 	return sr->val;
 }
 
@@ -2515,7 +2822,7 @@ static double expfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp_freq(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expfreq(x, l).");
+	else yyargcnterr("expfreq(x, l)");
 	return sr->val;
 }
 
@@ -2526,7 +2833,7 @@ static double lognormdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognormdist(x, mean, SD).");
+	else yyargcnterr("lognormdist(x, mean, SD)");
 	return sr->val;
 }
 
@@ -2537,7 +2844,7 @@ static double lognormfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = lognorm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognormfreq(x, mean, SD).");
+	else yyargcnterr("lognormfreq(x, mean, SD)");
 	return sr->val;
 }
 
@@ -2548,7 +2855,7 @@ static double lognorminv(YYSTYPE *sr)
         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], exp(sr->a_data[1]));
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
+	else yyargcnterr("lognorminv(p, mean, SD)");
 	return sr->val;
 }
 
@@ -2559,7 +2866,7 @@ static double chidist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  chidist(x, df).");
+	else yyargcnterr("chidist(x, df)");
 	return sr->val;
 }
 
@@ -2570,7 +2877,7 @@ static double chifreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("chifreq(x, df)");
 	return sr->val;
 }
 
@@ -2581,7 +2888,7 @@ static double chiinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  chiinv(p, df).");
+	else yyargcnterr("chiinv(p, df)");
 	return sr->val;
 }
 
@@ -2592,7 +2899,7 @@ static double tdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  tdist(x, df).");
+	else yyargcnterr("tdist(x, df)");
 	return sr->val;
 }
 
@@ -2603,7 +2910,7 @@ static double tfreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("tfreq(x, df)");
 	return sr->val;
 }
 
@@ -2617,7 +2924,7 @@ static double tinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		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).");
+	else yyargcnterr("tinv(p, df)");
 	return sr->val;
 }
 
@@ -2628,7 +2935,7 @@ static double poisdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  poisdist(x, mean).");
+	else yyargcnterr("poisdist(x, mean)");
 	return sr->val;
 }
 
@@ -2639,7 +2946,7 @@ static double poisfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0]));
 		}
-	else yyargserr("Wrong number of arguments\nin call to  poisfreq(x, mean).");
+	else yyargcnterr("poisfreq(x, mean)");
 	return sr->val;
 }
 
@@ -2650,7 +2957,7 @@ static double fdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  fdist(x, df1, df2).");
+	else yyargcnterr("fdist(x, df1, df2)");
 	return sr->val;
 }
 
@@ -2661,7 +2968,7 @@ static double ffreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("ffreq(x, df1, df2)");
 	return sr->val;
 }
 
@@ -2672,119 +2979,295 @@ static double finv(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  finv(p, df1, df2).");
+	else yyargcnterr("finv(p, df1, df2)");
 	return sr->val;
 }
 
-static double ksdist(YYSTYPE *sr)
+static double weibdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
-		sr->val = ks_dist((int)sr->a_data[0], sr->a_data[1]);
+		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  ksdist(n, D).");
+	else yyargcnterr("weibdist(x, shape[, scale=1])");
 	return sr->val;
 }
 
-static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double weibfreq(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yyargcnterr("weibfreq(x, shape[, scale=1])");
+	return sr->val;
 }
 
-static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double weibinv(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(weib_dist,sr->a_data[1], 1.0, sr->a_data[0], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(weib_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0],sr->a_data[2]);
 		}
-	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yyargcnterr("weibinv(p, shape[, scale=1])");
+	return sr->val;
 }
 
-static double kendall(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double cauchydist(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("cauchydist(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double cauchyfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("cauchyfreq(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double cauchyinv(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(cauch_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(cauch_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargcnterr("cauchyinv(p, location[, scale=1])");
+	return sr->val;
+}
+
+static double logisdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("logisdist(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double logisfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("logisfreq(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double logisinv(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(logis_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(logis_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargcnterr("logisinv(p, location[, scale=1])");
+	return sr->val;
+}
+
+static void pearson(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 3) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
+		}
+	else yybadargerr("pearson(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
+}
+
+static void spearman(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("spearman(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void kendall(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-	if(!(dest)) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
+		}
+	else yybadargerr("kendall(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
+}
+
+static void regression(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(!dest && !arr) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		lval->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nregression(range1; range2; \"dest\").");
-	return sr1->val;
+	else yybadargerr("regression(range1; range2; \"dest\")");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double covar(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void _covar(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	if(!sr1 || !sr2) return;
+	lval->val = 0.0;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		lval->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, 0L, curr_data);
 		}
-	else yyargserr("Bad arguments in call to function\ncovar(range1; range2).");
-	return sr1->val;
+	else yybadargerr("covar(range1; range2)");
+	return;
 }
 
-static double ttest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ttest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         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, 0L);
+		lval->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ttest(array1; array2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double ttest2(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ttest2(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	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_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 6) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count == sr1->a_count){
+		lval->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nttest2(range1; range2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ttest2(range1; range2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double utest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void utest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         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, 0L);
+		lval->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("utest2(array1; array2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ftest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){
-		sr1->val = sr2->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		lval->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nftest(range1; range2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ftest(range1; range2[;\"dest\"])");
 }
 
 static double p_tukey(YYSTYPE *sr)
@@ -2797,7 +3280,7 @@ static double p_tukey(YYSTYPE *sr)
 	else if(sr->a_data && sr->a_count == 3){
 		sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to ptukey(q, nm, df[, nr = 1]).");
+	else yyargcnterr("ptukey(q, nm, df[, nr = 1])");
 	return sr->val;
 }
 
@@ -2811,7 +3294,7 @@ static double q_tukey(YYSTYPE *sr)
 	else if(sr->a_data && sr->a_count == 3){
 		sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to qtukey(p, nm, df[, nr = 1]).");
+	else yyargcnterr("qtukey(p, nm, df[, nr = 1])");
 	return sr->val;
 }
 
@@ -2820,7 +3303,7 @@ static double fill(YYSTYPE *sr, char *dest)
 	AccRange *ar;
 	int i, r, c;
 
-	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0]) return 0.0;
+	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0] || bNoWrite) return 0.0;
 	if(ar = new AccRange(dest)) {
 		for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) {
 			curr_data->SetValue(r, c, sr->a_data[i]);
@@ -2933,7 +3416,7 @@ static double seconds(double dv)
 
 static void fdate(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -2942,7 +3425,7 @@ static void fdate(YYSTYPE *dst, YYSTYPE *src)
 
 static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -2951,7 +3434,7 @@ static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
 
 static void ftime(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -2999,6 +3482,64 @@ static void asort(YYSTYPE *dst, YYSTYPE *src)
 		}
 }
 
+static void _randarr(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
+		break;
+	default:
+		dst->a_data = randarr(src->a_data, src->a_count, &idum);
+		dst->a_count = src->a_count;
+		}
+}
+
+static void _resample(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
+		break;
+	default:
+		dst->a_data = resample(src->a_data, src->a_count, &idum);
+		dst->a_count = src->a_count;
+		}
+}
+
+static void mkarr(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char*fmt)
+{
+	AccRange *rD;
+	int i, n, r, c;
+	anyResult ares;
+
+	if(fmt || !sr2 || !sr1 || !sr1->text) yyargcnterr("mkarr(range, MD)");
+	if(!(rD = new AccRange(sr1->text)) || !(n = rD->CountItems())) {
+		yybadargerr("mkarr(range, MD)");
+		}
+	res->a_data = PushArray((double*)calloc(n, sizeof(double)));
+	for(i = 0, rD->GetFirst(&c, &r); i < n; i++) {
+		rD->GetNext(&c, &r);
+		if(curr_data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE) res->a_data[i] = ares.value;
+		else res->a_data[i] = sr2->val;
+		res->a_count = i;
+		}
+	if(rD) delete rD;
+}
+
 static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt)
 {
 	int n;
@@ -3018,9 +3559,26 @@ static double _crank(YYSTYPE *src)
 	if(!src) return tmp;
 	tmp = 0.0;
 	if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp);
+	if(src->type == RANGEARR) RangeData.rmData(src->a_data, src->a_count);
 	return tmp;
 }
 
+static void subarr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	int i, pos2;
+
+	if(!src1->a_data) yybadargerr("subarr(array; pos1[; pos2])");
+	else {
+		if(src3) pos2 = (int)(src3->val);
+		else pos2 = src1->a_count;
+		dst->type = ARR;
+		dst->a_data = PushArray((double*)malloc(src1->a_count*sizeof(double)));
+		for(i = (int)(src2->val), dst->a_count = 0; i <= pos2 && i < src1->a_count; i++) {
+			dst->a_data[dst->a_count++] = src1->a_data[i];
+			}
+		}
+}
+
 static void ltrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
@@ -3061,14 +3619,20 @@ static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 
 static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
 {
-	dst->type = STR;
-	dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+	if(src3) {
+		dst->type = STR;
+		dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+		}
+	else yyargcnterr("strrepl(search; replace; haystack)");
 }
 
 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)));
+	if(src3) {
+		dst->type = STR;
+		dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val)));
+		}
+	else yyargcnterr("substr(text; pos1; pos2)");
 }
 
 static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum)
@@ -3141,13 +3705,15 @@ static void uc_word(YYSTYPE *dst, YYSTYPE *src)
 	else dst->text = 0L;
 }
 
-static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+static void exec_block(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, bool namespc)
 {
 	char *cmd = 0L;
 	int cmd_pos = 0, cmd_size, r, c;
 	AccRange *ar = 0L;
 	anyResult res, *eres;
+	YYSTYPE evsrc, evdst;
 
+	if(bNoExec) return;
 	if(!src1 || !src1->text || !src1->text[0]) return;
 	if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) {
 		if(src2 && src2->text[0] && src2->text[0]) {
@@ -3175,7 +3741,14 @@ static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 				break;
 				}
 			}while(ar->GetNext(&c, &r));
-		eres = do_formula(curr_data, cmd);
+		if(namespc) {
+			eres = do_formula(curr_data, cmd);
+			}
+		else {
+			memset(&evsrc, 0, sizeof(YYSTYPE));	memset(&evdst, 0, sizeof(YYSTYPE));
+			evsrc.text = cmd;			eval(&evdst, &evsrc);
+			eres = &line_res;
+			}
 		switch(eres->type) {
 		case ET_BOOL:
 			dst->type = BOOLVAL;	dst->val = eres->value;
@@ -3194,6 +3767,17 @@ static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 	if(cmd) free(cmd);	if(ar) delete ar;
 }
 
+static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	exec_block(dst, src1, src2, true);
+}
+
+static void call(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	exec_block(dst, src1, src2, false);
+}
+
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -3285,6 +3869,13 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
+	INIT_SYM(YYFNC3, "mkarr", mkarr),
+	INIT_SYM(YYFNC, "randarr", _randarr),		INIT_SYM(YYFNC, "resample", _resample),
+	INIT_SYM(AFNCT, "weibdist", weibdist),		INIT_SYM(AFNCT, "weibfreq", weibfreq),
+	INIT_SYM(AFNCT, "weibinv", weibinv),		INIT_SYM(AFNCT, "cauchydist", cauchydist),
+	INIT_SYM(AFNCT, "cauchyfreq", cauchyfreq),	INIT_SYM(AFNCT, "cauchyinv", cauchyinv),
+	INIT_SYM(AFNCT, "logisdist", logisdist),	INIT_SYM(AFNCT, "logisfreq", logisfreq),
+	INIT_SYM(AFNCT, "logisinv", logisinv),		INIT_SYM(YYFNC2, "call", call),
 	INIT_SYM(AFNCT, "ptukey", p_tukey),		INIT_SYM(AFNCT, "qtukey", q_tukey),
 	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
 	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
@@ -3302,12 +3893,12 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
 	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
 	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),
-	INIT_SYM(FUNC2, "covar", covar),		INIT_SYM(YYFNC2, "exec", exec),
-	INIT_SYM(FUNC3, "utest", utest),		INIT_SYM(FUNC2, "ttest2", ttest2),
-	INIT_SYM(FUNC3, "ttest", ttest),		INIT_SYM(FUNC3, "ftest", ftest),
+	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(YYFNC3, "pearson", pearson),
+	INIT_SYM(YYFNC3, "spearman", spearman),		INIT_SYM(YYFNC3, "kendall", kendall),		
+	INIT_SYM(YYFNC3, "correl", pearson),		INIT_SYM(YYFNC3, "regression", regression),
+	INIT_SYM(YYFNC2, "covar", _covar),		INIT_SYM(YYFNC2, "exec", exec),
+	INIT_SYM(YYFNC3, "utest", utest),		INIT_SYM(YYFNC3, "ttest2", ttest2),
+	INIT_SYM(YYFNC3, "ttest", ttest),		INIT_SYM(YYFNC3, "ftest", ftest),
 	INIT_SYM(AFNCT, "variance", variance),		INIT_SYM(AFNCT, "stdev", stdev),
 	INIT_SYM(AFNCT, "sterr", sterr),		INIT_SYM(AFNCT, "min", min),
 	INIT_SYM(AFNCT, "max", max),			INIT_SYM(AFNCT, "count", count),
@@ -3321,12 +3912,12 @@ void InitArithFuncs(DataObj *d)
 	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, "ffreq", ffreq),		INIT_SYM(AFNCT, "ksdist", ksdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),		INIT_SYM(YYFNC3, "subarr", subarr),
 	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),
 	INIT_SYM(AFNCT, "binomdist",binomdist),		INIT_SYM(AFNCT, "binomfreq",binomfreq),
-	INIT_SYM(AFNCT, "normdist", normdist),
+	INIT_SYM(AFNCT, "normdist", normdist),		INIT_SYM(AFNCT, "average", mean),
 	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),
@@ -3422,6 +4013,14 @@ getsym (unsigned int h_name, unsigned int h2_name, char *sym_name)
 static int
 push(YYSTYPE *res, YYSTYPE *val)
 {
+	double *tmparr;
+
+	if(res->type == RANGEARR || res->text) {
+		if((tmparr = res->a_data) && (res->a_data = PushArray((double*)malloc((res->a_count+1)*sizeof(double))))){
+			memcpy(res->a_data, tmparr, res->a_count * sizeof(double));
+			res->type = ARR;	res->text = 0L;
+			}
+		}
 	if(val->a_data) {
 		if(!(res->a_data)) {
 			if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
@@ -3453,29 +4052,10 @@ push(YYSTYPE *res, YYSTYPE *val)
 }
 
 static int
-range_array(YYSTYPE * res, char *range)
+range_array(YYSTYPE *res, char *range)
 {
-	AccRange *r;
-	int row, col;
-	anyResult ares;
-
-	if(!range || !range[0] || !(r = new AccRange(range))) return 0;
-	if(!r->GetFirst(&col, &row) || !(res->a_data =  PushArray((double*)malloc(r->CountItems() * sizeof(double))))) {
-		delete(r);
-		return 0;
-		}
-	parse_level++;
-	for(res->a_count = 0; r->GetNext(&col, &row); ) {
-		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
-			switch(ares.type) {
-			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
-				res->a_data[res->a_count++] = ares.value;
-				break;
-				}
-			}
-		}
-	parse_level--;
-	delete(r);
+	RangeData.GetData(range, &res->a_data, &res->a_count, &res->text); 
+	res->val = 0.0;		res->type = RANGEARR;
 	return 1;
 }
 
@@ -3508,7 +4088,7 @@ range_array2(YYSTYPE *res1, YYSTYPE *res2)
 			res2->a_data[res2->a_count++] = ares2.value;
 			}
 		}
-	parse_level--;
+	parse_level--;	res1->type = res2->type = ARR;
 	delete(r1);	delete(r2);
 	return 1;
 }
@@ -3705,7 +4285,13 @@ static char *copy_block()
  			if(src[i] == last[level]) {
 				if(level) level--;
 				else {
-					res[j-1] = ';';	res[j] = 0;	buff_pos += j;
+					if(res[j-2] == ';'){
+						res[j-1] = 0;
+						}
+					else {
+						res[j-1] = ';';		res[j] = 0;	
+						}
+					buff_pos += j;
 					return res;
 					}
 				}
@@ -3721,6 +4307,7 @@ static char *copy_block()
 				}
 			}
 		}
+	if(res[j-1] == ';') j--;
 	res[j] = ';';	res[j+1] = 0;		buff_pos += j;
 	return res;
 }
@@ -3734,7 +4321,7 @@ static double for_loop(char *block1, char *block2)
 	YYSTYPE yyres, yysrc;
 	symrec *var;
 
-	if(!block1 || !block1[0]) return 0.0;
+	if(!block1 || !block1[0] || bNoExec) return 0.0;
 	bb1 = bb2 = bb3 = 0L;		parse_level++;
 	cb1 = (int)strlen(block1);
 	last_buffer = buffer;		last_buff_pos = buff_pos;
@@ -3858,9 +4445,8 @@ static int yylex()
 				tmp_txt[i++] = (char)c; 
 				}
 			tmp_txt[i] = 0;
-			yylval.text = PushString(tmp_txt);
-			range_array(&yylval, yylval.text);
-			yylval.val = 0.0;
+			RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text); 
+			yylval.val = 0.0; 
 			return yylval.type = RANGEARR;
 			}
 		tmp_txt[i] = 0;
@@ -3946,6 +4532,9 @@ static int yylex()
 			else syntax_level->last_tok = 0;
 			}
 		break;
+	case ',':
+		if(syntax_level && syntax_level->last_tok == '(') return LSEP;
+		break;
 	case '*':
 		if(buffer[buff_pos] == '=') tok = MULEQ;
 		break;
@@ -3985,6 +4574,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	int length, parse_res, res_mode = 0;
 
 	if(x1 < x2) step = fabs(step);
+	else if(x1 == x2) return false;
 	else step = -fabs(step);
 	if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT))))
 		return false;
@@ -4157,9 +4747,9 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
 				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:
-			case YYFNC2:	case YYFNC3:
+			case FNCT:	case FUNC1:	case AFNCT:	case SFNCT:
+			case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:	case YYFNC2:
+			case YYFNC3:
 				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case COLC:
@@ -4168,12 +4758,18 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
 			case PSEP:
 				res[pos++] = ';';
 				break;
+			case LSEP:
+				res[pos++] = ',';
+				break;
 			case CLVAL:
 				res[pos++] = '$';	res[pos++] = '$';
 				break;
 			case CLAUSE:
 				pos += rlp_strcpy(res+pos, length2-pos, " where ");
 				break;
+			case DIM:
+				pos += rlp_strcpy(res+pos, length2-pos, "dim ");
+				break;
 			case VAR:
 				curr_sym->InitSS();
 				if(curr_sym->col >= 0 && curr_sym->row >= 0) {
diff --git a/mfcalc.y b/mfcalc.y
index 1676c43..69a4162 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -102,19 +102,20 @@ static char *last_err_desc = 0L;	//short error description
 static char *buffer = 0L;		//the current command buffer
 static int buff_pos = 0;
 static bool bRecent = false;		//rearrange functions
+static bool bNoWrite, bNoExec;		//while editing ...
 static int parse_level = 0;		//count reentrances into parser
-#define MAX_PARSE 20			//maximum number of reentances 
+#define MAX_PARSE 50			//maximum number of recursive reentances 
 %}
 
 %token <val>  NUM BOOLVAL STR ARR BLOCK PBLOCK IBLOCK PI E CLVAL PSEP IF ELSE 
 %token <val>  BTRUE BFALSE DATE1 TIME1 DATETIME1 DIM WHILE FOR INARR RANGEARR
 %token <val>  RETURN BREAK
-%token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 FUNC2 FUNC3 TXT SRFUNC YYFNC
+%token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 TXT SRFUNC YYFNC
 %token <tptr> FUNC4 YYFNC2 YYFNC3
 %type  <val>  exp str_exp arr bool block anyarg
 
 %right  '=' ADDEQ SUBEQ MULEQ DIVEQ
-%left	','			/* list separator */
+%left	LSEP			/* list separator */
 %left	CLAUSE			/* clause (where) operator */
 %left	SER
 %right	COLC			/* conditional sep. */
@@ -173,9 +174,9 @@ range:
 
 arr:	ARR			{;}
 	|exp			{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;}}
-	|arr ',' arr		{push(&yyval, &yyvsp[0]);yyval.type = ARR;}
-	|arr CLAUSE exp		{exec_clause(&yyval);yyval.type = ARR;}
-	|range			{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;}
+	|arr LSEP arr		{push(&yyval, &yyvsp[0]);yyval.type = ARR;}
+	|arr CLAUSE exp		{exec_clause(&yyval);}
+	|range			{range_array(&yyval, yyvsp[0].text);}
 	|NUM SER NUM		{if($1 < $3 && (yyval.a_data = PushArray((double*)malloc((int)($3-$1+2)*sizeof(double)))))
 					for(yyval.a_count=0; $1<=$3; yyval.a_data[yyval.a_count++] = $1, $1 += 1.0 ); yyval.type = ARR;}
 ;
@@ -199,7 +200,7 @@ block:	BLOCK | IBLOCK;
 anyarg: exp | str_exp;
 
 exp:	NUM				{$$ = $1; yyval.type = NUM;}
-	|RANGEARR			{yyval.type = ARR;}
+	|RANGEARR
   	|bool				{$$ = $1; yyval.type = BOOLVAL;}
         |TXT				{$$ = 0.0;}
 	|CLVAL				{$$ = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;}
@@ -231,10 +232,6 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|SFNCT '(' exp ',' str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
 	|SFNCT '(' str_exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
 	|SFNCT '(' exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
-	|FUNC2 '(' anyarg PSEP anyarg ')' {range_array2(&yyvsp[-3], &yyvsp[-1]);$$ = $1->fnctptr ? ((*$1->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)) : 0.0; yyval.type = NUM;}
-	|FUNC2 '(' anyarg PSEP anyarg PSEP anyarg ')' {range_array2(&yyvsp[-5], &yyvsp[-3]); $$ = $1->fnctptr ? ((*$1->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
-	|FUNC3 '(' arr PSEP arr ')'	{$$= $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L)) : 0.0;}
-	|FUNC3 '(' arr PSEP arr PSEP range ')' {$$=$1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;}
 	|FUNC4 '(' exp PSEP exp PSEP arr PSEP range ')' {proc_clause(&yyvsp[-3]); $$=$1->fnctptr ? (*$1->fnctptr)($3, $5, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;}
 	|FUNC1 '(' arr PSEP range ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;}
 	|FUNC1 '(' arr PSEP RANGEARR ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;}
@@ -242,7 +239,8 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|YYFNC '(' arr ')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1]);}
 	|YYFNC2 '(' anyarg PSEP anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
 	|YYFNC2 '(' anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1], 0L);}
-	|YYFNC3 '(' anyarg PSEP anyarg PSEP anyarg')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' anyarg PSEP anyarg PSEP anyarg ')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC3 '(' anyarg PSEP anyarg ')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);}
 	|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;
@@ -265,19 +263,25 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 					yyval.type = ARR; $2->SetValue(&yyval,&yyval);}
 	|exp '[' exp ']'	{if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) $$ = yyvsp[-3].a_data[(int)yyvsp[-1].val];
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
-	|exp '[' exp ']' '=' exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) $$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] = $6;
+	|exp '[' exp ']' '=' exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
+				{$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] = $6; 
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|exp '[' exp ']' ADDEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
-				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] += $6;
+				{$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] += $6;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|exp '[' exp ']' SUBEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
-				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= $6;
+				{$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= $6;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|exp '[' exp ']' MULEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
-				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= $6;
+				{$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= $6;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|exp '[' exp ']' DIVEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ 
-				if($6 != 0.0) $$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= $6;
+				if($6 != 0.0) {$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= $6;
+				if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
 				else {$$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|NUM ':' NUM ':' NUM	{make_time(&yyval, $1, $3, $5+1.0e-10);}
@@ -289,7 +293,276 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 ;
 %%
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Cache spreadsheet data for repeated access
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SsRangeData {
+typedef struct _rng_data {
+	_rng_data *next;
+	unsigned int h1, h2;
+	RECT rec;
+	double *vals;
+	char *name;
+	int nvals;
+	double dSum, dMean, dQuart1, dQuart2, dQuart3;
+	bool bSum, bMean, bQuart1, bQuart2, bQuart3;
+	}rng_data;
+
+public:
+	SsRangeData();
+	~SsRangeData();
+	void Clear();
+	bool GetData(char *rng_desc,  double **vals, int *nvals, char **name);
+	void rmData(double *vals, int nvals);
+	void cellModified(int row, int col);
+	double sum(double *vals, int nvals);
+	double mean(double *vals, int nvals);
+	double quartile1(double *vals, int nvals);
+	double quartile2(double *vals, int nvals);
+	double quartile3(double *vals, int nvals);
+
+private:
+	rng_data *RngData;
+
+	bool FindData(unsigned int h1, unsigned int h2, rng_data **rda);
+	bool FindData(double *vals, int nvals, rng_data **rda);
+	bool SetArray(rng_data *rda, char *range);
+	void do_quartiles(rng_data *rda);
+}; 
+ 
+SsRangeData::SsRangeData()
+{
+	RngData = 0L;
+} 
+
+SsRangeData::~SsRangeData()
+{
+	Clear();
+}
+
+void
+SsRangeData::Clear()
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		nxt = RngData->next;
+		if(RngData->vals) free(RngData->vals);
+		if(RngData->name) free(RngData->name);
+		free(RngData); 		RngData = nxt;
+		}
+}
+
+bool
+SsRangeData::FindData(unsigned int h1, unsigned int h2, rng_data **rda)
+{ 
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(nxt->h1 == h1 && nxt->h2 == h2) {
+			*rda = nxt; 	return true;
+			}
+		nxt = nxt->next;
+		}
+	return false;
+}
+
+bool
+SsRangeData::FindData(double *vals, int nvals, rng_data **rda)
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(nxt->vals == vals && nxt->nvals == nvals) {
+			*rda = nxt;	return true;
+			}
+		nxt = nxt->next;
+		}
+	return false;
+}
+
+bool
+SsRangeData::SetArray(rng_data *rda, char *range)
+{ 
+	AccRange *r;
+	int row, col;
+	anyResult ares;
+
+	if(!range || !range[0] || !(r = new AccRange(range))) return false;
+	if(!r->GetFirst(&col, &row) || !(rda->vals =  (double*)malloc(r->CountItems() * sizeof(double)))) {
+		delete(r); 		return false;
+		} 
+	r->BoundRec(&rda->rec);
+	parse_level++;			r->GetFirst(&col, &row);
+	for(rda->nvals = 0; r->GetNext(&col, &row); ) {
+		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
+			switch(ares.type) {
+			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
+				rda->vals[rda->nvals++] = ares.value;
+				break;
+				}
+			}
+		}
+	rda->name = (char*)memdup(range, (int)strlen(range)+1, 0);
+	parse_level--;
+	delete(r);
+	return true;
+}
+
+void
+SsRangeData::rmData(double *vals, int nvals)
+{
+	rng_data *rda, *rmrda;
+
+	if(!FindData(vals, nvals, &rmrda)) return;
+	if(rmrda == RngData) RngData = RngData->next;
+	else {
+		rda = RngData;
+		while(rda->next && rda->next != rmrda) rda = rda->next;
+		if(rda->next == rmrda) rda->next = rmrda->next;
+		else return;
+		}
+	rda = RngData;
+	while(rda) {
+		if(((rda->rec.top <= rmrda->rec.top && rda->rec.bottom >= rmrda->rec.top)
+			|| (rda->rec.top <= rmrda->rec.bottom && rda->rec.top >= rmrda->rec.top))
+			&&((rda->rec.left <= rmrda->rec.left && rda->rec.right >= rmrda->rec.left)
+			|| (rda->rec.left <= rmrda->rec.right && rda->rec.left >= rmrda->rec.left))){
+			rmData(rda->vals, rda->nvals);
+			rda = RngData;
+			}
+		else rda = rda->next;
+		}
+	if(rmrda->vals) free(rmrda->vals);
+	if(rmrda->name) free(rmrda->name);
+	free(rmrda);
+}
+
+void
+SsRangeData::cellModified(int row, int col)
+{
+	rng_data *nxt;
+
+	nxt = RngData;
+	while(nxt) {
+		if(col >= nxt->rec.left && col <= nxt->rec.right && row >= nxt->rec.top && col <= nxt->rec.bottom){
+			rmData(nxt->vals, nxt->nvals);
+			nxt = RngData;
+			}
+		else nxt = nxt->next;
+		}
+	return;
+}
+
+void
+SsRangeData::do_quartiles(rng_data *rda)
+{
+	double *vals;
+
+	if(rda->vals && rda->nvals && (vals = (double*)memdup(rda->vals, rda->nvals*sizeof(double), 0))){
+		d_quartile(rda->nvals, vals, &rda->dQuart1, &rda->dQuart2, &rda->dQuart3);
+		free(vals);
+		}
+	rda->bQuart1 = rda->bQuart2 = rda->bQuart3 = true;
+}
+
+bool  
+SsRangeData::GetData(char *rng_desc, double **vals, int *nvals, char **name)
+{ 
+	rng_data *rda;
+	unsigned int h1, h2;
+
+	h1 = HashValue((unsigned char*) rng_desc);
+	h2 = Hash2((unsigned char*) rng_desc);
+	if(FindData(h1, h2, &rda)) {
+		*vals = rda->vals;	*nvals = rda->nvals;
+		if(name) *name = rda->name;
+		return true;
+		}
+	if(!(rda = (rng_data*) calloc(1, sizeof(rng_data))))return false;
+	SetArray(rda, rng_desc);
+	*vals = rda->vals; 		*nvals = rda->nvals;
+	if(name) *name = rda->name;
+	rda->h1 = h1; 			rda->h2 = h2; 
+	rda->next = RngData;		RngData = rda;
+	return true;
+}
+
+double
+SsRangeData::sum(double *vals, int nvals)
+{
+	rng_data *rda;
+	int i;
+	double tmp;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bSum) return rda->dSum;
+		for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
+		rda->dSum = tmp;	rda->bSum = true;
+		return rda->dSum;
+		}
+	for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i];
+	return tmp;
+}
+
+double
+SsRangeData::mean(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bMean) return rda->dMean;
+		rda->dMean = d_amean(nvals, vals);
+		rda->bMean = true;
+		return rda->dMean;
+		}
+	return d_amean(nvals, vals);
+}
+
+double
+SsRangeData::quartile1(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart1) return rda->dQuart1;
+		do_quartiles(rda);	return rda->dQuart1;
+		}
+	return HUGE_VAL;
+}
+
+double
+SsRangeData::quartile2(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart2) return rda->dQuart2;
+		do_quartiles(rda);	return rda->dQuart2;
+		}
+	return HUGE_VAL;
+}
+
+double
+SsRangeData::quartile3(double *vals, int nvals)
+{
+	rng_data *rda;
+
+	if(FindData(vals, nvals, &rda)) {
+		if(rda->bQuart3) return rda->dQuart3;
+		do_quartiles(rda);	return rda->dQuart3;
+		}
+	return HUGE_VAL;
+}
+
+static SsRangeData RangeData;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // The symrec class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) 
 {
 	h_name = h_n;	h2_name = h2_n;		type = typ;
@@ -301,8 +574,8 @@ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt)
 
 symrec::~symrec()
 {
-	if(name) free(name);	name = 0L;
-	if(text) free(text);	text = 0L;
+	if(name) free(name);		name = 0L;
+	if(text) free(text);		text = 0L;
 }
 
 double
@@ -329,6 +602,7 @@ symrec::GetValue(void *re)
 	anyResult ares;
 	YYSTYPE *res = (YYSTYPE*)re;
 
+	if(!res) return;
 	if(isSSval) {
 		if(row < 0 && col < 0) InitSS();
 		res->a_data = 0L;	res->a_count = 0;
@@ -368,13 +642,12 @@ symrec::GetValue(void *re)
 		}
 	if(!isValid) NoInit();
 	if(a_data && a_count) {
-		if(text && text[0]) res->text = PushString(text);
-		else res->text = 0L;
-		res->a_data = a_data;	res->a_count = a_count;
-		res->val = 0.0;		res->type = ARR;
+		res->text = 0L;		res->a_count = a_count;
+		res->a_data = a_data;	res->val = 0.0;
+		res->type = ARR;
 		}
 	else if(text && text[0]) {
-		res->text = PushString(text);
+		res->text = text;
 		res->a_data = 0L;	res->a_count = 0;
 		res->val = 0.0;		res->type = STR;
 		}
@@ -388,10 +661,11 @@ symrec::GetValue(void *re)
 double 
 symrec::SetValue(double v)
 {
-	if(isSSval) {
+	if(isSSval && !bNoWrite) {
 		if(row < 0 && col < 0) InitSS();
 		if(curr_data->SetValue(row, col, v)){
 			if(curr_data) curr_data->Command(CMD_UPDATE, 0L, 0L);
+			RangeData.cellModified(row, col);
 			return var = v;
 			}
 		isSSval = false;
@@ -408,11 +682,12 @@ symrec::SetValue(void* d, void* s)
 	YYSTYPE *dest = (YYSTYPE*)d;
 	YYSTYPE *src = (YYSTYPE*)s;
 
-	if(isSSval && curr_data) {
+	if(isSSval && curr_data && !bNoWrite) {
 		if(row < 0 && col < 0) InitSS();
 		if(last_err_desc) curr_data->SetText(row, col, last_err_desc);
 		else if(src->type == STR) curr_data->SetText(row, col, src->text);
-		else if(src->type == ARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY");
+		else if(src->type == ARR || src->type == RANGEARR || (src->a_data)) 
+			curr_data->SetText(row, col, "#ARRAY");
 		else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text);
 		else {
 			if(curr_data->SetValue(row, col, src->val))
@@ -422,14 +697,17 @@ symrec::SetValue(void* d, void* s)
 				}
 			}
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
+		RangeData.cellModified(row, col);
 		}
-	isValid = true;
-	var = src->val;
-	if(text) free(text);		text = 0L;
-	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);
+	isValid = true;			var = src->val;
+	if(src->a_data && src->a_count) {
+		a_data = src->a_data;		a_count = src->a_count;
+		}
+	else if(src->text && src->text[0] && src->text != text) {
+		if(text) free(text);		text = 0L;
+		text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0);
+		}
+	if(d) GetValue(d);
 	return;
 }
 
@@ -465,7 +743,14 @@ symrec::NoInit()
 #endif
 	yywarn(message, true);
 }
-
+ 
+void LockData(bool lockExec, bool lockWrite) 
+{ 
+	RangeData.Clear();
+	bNoWrite = lockWrite;
+	bNoExec = lockExec;
+} 
+ 
 static void yyerror(char *s)
 {  
 	//called by yyparse on error
@@ -475,11 +760,35 @@ static void yyerror(char *s)
 
 static void yyargserr(char *s)
 {
-	//call from function on argument type/number mismatch
-	yyerror(s);
-	last_err_desc = "#ARGS";
+	//call from function on argument type mismatch
+	yyerror(s);	last_err_desc = "#ARGS";
+}
+
+static void yyargcnterr(char *s)
+{
+	//call from function on argument number mismatch
+	static char arg_cnt_err[80];
+	int cb;
+
+	cb = rlp_strcpy(arg_cnt_err, 80, "Wrong number of arguments\nin call to ");
+	cb += rlp_strcpy(arg_cnt_err+cb, 80-cb, s);
+	rlp_strcpy(arg_cnt_err+cb, 80-cb, ".");
+	yyargserr(arg_cnt_err);
+}
+
+static void yybadargerr(char *s)
+{
+	//call from function on argument number mismatch
+	static char bad_arg_err[80];
+	int cb;
+
+	cb = rlp_strcpy(bad_arg_err, 80, "Bad arguments in call to function\n");
+	cb += rlp_strcpy(bad_arg_err+cb, 80-cb, s);
+	rlp_strcpy(bad_arg_err+cb, 80-cb, ".");
+	yyargserr(bad_arg_err);
 }
 
+
 static char txt_tokenerr[80];
 static void yytokenerr(int c)
 {
@@ -549,7 +858,7 @@ static void store_res(YYSTYPE *res)
 		line_res.value = 0.0;
 		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
 		}
-	else if((res->type == ARR || (res->a_data)) && res->a_count == 1) {
+	else if((res->type == ARR || res->type == RANGEARR || (res->a_data)) && res->a_count == 1) {
 		line_res.type = ET_VALUE;
 		line_res.value = res->a_data[0];
 		}
@@ -557,7 +866,7 @@ static void store_res(YYSTYPE *res)
 		line_res.type = ET_VALUE;
 		line_res.value = res->val;
 		}
-	else if(res->type == ARR || (res->a_data)) {
+	else if(res->type == ARR || res->type == RANGEARR || (res->a_data)) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
 		line_res.a_data = res->a_data;
@@ -646,6 +955,7 @@ static int eval(YYSTYPE *dst, YYSTYPE *sr)
 	int s_buff_pos, s_yychar, s_yynerrs, length, parse_res;
 	anyResult *ar;
 
+	if(bNoExec) return 0;
 	if(!sr || !sr->text || !sr->text[0]) return 1;
 	s_buffer = buffer;		s_buff_pos = buff_pos;
 	s_yychar = yychar;		s_yynerrs = yynerrs;
@@ -762,7 +1072,10 @@ static double sum(YYSTYPE *sr)
 	int i;
 
 	if(!sr) return 0.0;
-	if(sr->a_data){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.sum(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data){
 		for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i];
 		}
 	else sr->val = 0.0;
@@ -772,9 +1085,13 @@ static double sum(YYSTYPE *sr)
 static double mean(YYSTYPE *sr) 
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.mean(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		sr->val = d_amean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -784,6 +1101,7 @@ static double kurt(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count > 3){
 		sr->val = d_kurt(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -793,6 +1111,7 @@ static double skew(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count > 2){
 		sr->val = d_skew(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -808,6 +1127,7 @@ static double gmean(YYSTYPE *sr)
 			}
 		sr->val = d_gmean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -823,33 +1143,46 @@ static double hmean(YYSTYPE *sr)
 			}
 		sr->val = d_hmean(sr->a_count, sr->a_data );
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile1(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile1(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile2(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile2(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
 static double quartile3(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
+	if(sr->type == RANGEARR && sr->a_data) {
+		sr->val = RangeData.quartile3(sr->a_data, sr->a_count);
+		}
+	else if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
 		}
+	else sr->val = 0.0;
 	return sr->val;
 }
 
@@ -890,7 +1223,7 @@ static double beta(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = betaf(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  beta(u, v).");
+	else yyargcnterr("beta(u, v)");
 	return sr->val;
 }
 
@@ -901,7 +1234,7 @@ static double _gammp(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammp(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  gammp(a, x).");
+	else yyargcnterr("gammp(a, x)");
 	return sr->val;
 }
 
@@ -912,7 +1245,7 @@ static double _gammq(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammq(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  gammq(a, x).");
+	else yyargcnterr("gammq(a, x)");
 	return sr->val;
 }
 
@@ -927,7 +1260,7 @@ static double _betai(YYSTYPE *sr)
 			}
 		sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  betai(a, b, x).");
+	else yyargcnterr("betai(a, b, x)");
 	return sr->val;
 }
 
@@ -938,7 +1271,7 @@ static double _bincof(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2){
 		sr->val = bincof(sr->a_data[0], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  bincof(n, k).");
+	else yyargcnterr("bincof(n, k)");
 	return sr->val;
 }
 
@@ -949,7 +1282,7 @@ static double binomdist(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 3){
 		sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  binomdist(s, n, p).");
+	else yyargcnterr("binomdist(s, n, p)");
 	return sr->val;
 }
 
@@ -962,7 +1295,7 @@ static double binomfreq(YYSTYPE *sr)
 		sr->val *= pow(sr->a_data[2], sr->a_data[0]);
 		sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  binomfreq(s, n, p).");
+	else yyargcnterr("binomfreq(s, n, p)");
 	return sr->val;
 }
 
@@ -973,7 +1306,7 @@ static double normdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  normdist(x, mean, SD).");
+	else yyargcnterr("normdist(x, mean, SD)");
 	return sr->val;
 }
 
@@ -984,7 +1317,7 @@ static double norminv(YYSTYPE *sr)
         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], sr->a_data[1]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
+	else yyargcnterr("norminv(p, mean, SD)");
 	return sr->val;
 }
 
@@ -995,7 +1328,7 @@ static double normfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  normfreq(x, mean, SD).");
+	else yyargcnterr("normfreq(x, mean, SD)");
 	return sr->val;
 }
 
@@ -1006,7 +1339,7 @@ static double expdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp_dist(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expdist(x, l).");
+	else yyargcnterr("expdist(x, l)");
 	return sr->val;
 }
 
@@ -1017,7 +1350,7 @@ static double expinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = exp_inv(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expinv(p, l).");
+	else yyargcnterr("expinv(p, l)");
 	return sr->val;
 }
 
@@ -1028,7 +1361,7 @@ static double expfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp_freq(sr->a_data[0], sr->a_data[1], 0.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  expfreq(x, l).");
+	else yyargcnterr("expfreq(x, l)");
 	return sr->val;
 }
 
@@ -1039,7 +1372,7 @@ static double lognormdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognormdist(x, mean, SD).");
+	else yyargcnterr("lognormdist(x, mean, SD)");
 	return sr->val;
 }
 
@@ -1050,7 +1383,7 @@ static double lognormfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = lognorm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognormfreq(x, mean, SD).");
+	else yyargcnterr("lognormfreq(x, mean, SD)");
 	return sr->val;
 }
 
@@ -1061,7 +1394,7 @@ static double lognorminv(YYSTYPE *sr)
         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], exp(sr->a_data[1]));
 		}
-	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
+	else yyargcnterr("lognorminv(p, mean, SD)");
 	return sr->val;
 }
 
@@ -1072,7 +1405,7 @@ static double chidist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  chidist(x, df).");
+	else yyargcnterr("chidist(x, df)");
 	return sr->val;
 }
 
@@ -1083,7 +1416,7 @@ static double chifreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("chifreq(x, df)");
 	return sr->val;
 }
 
@@ -1094,7 +1427,7 @@ static double chiinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  chiinv(p, df).");
+	else yyargcnterr("chiinv(p, df)");
 	return sr->val;
 }
 
@@ -1105,7 +1438,7 @@ static double tdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  tdist(x, df).");
+	else yyargcnterr("tdist(x, df)");
 	return sr->val;
 }
 
@@ -1116,7 +1449,7 @@ static double tfreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("tfreq(x, df)");
 	return sr->val;
 }
 
@@ -1130,7 +1463,7 @@ static double tinv(YYSTYPE *sr)
         if(sr->a_data && sr->a_count == 2) {
 		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).");
+	else yyargcnterr("tinv(p, df)");
 	return sr->val;
 }
 
@@ -1141,7 +1474,7 @@ static double poisdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  poisdist(x, mean).");
+	else yyargcnterr("poisdist(x, mean)");
 	return sr->val;
 }
 
@@ -1152,7 +1485,7 @@ static double poisfreq(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0]));
 		}
-	else yyargserr("Wrong number of arguments\nin call to  poisfreq(x, mean).");
+	else yyargcnterr("poisfreq(x, mean)");
 	return sr->val;
 }
 
@@ -1163,7 +1496,7 @@ static double fdist(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  fdist(x, df1, df2).");
+	else yyargcnterr("fdist(x, df1, df2)");
 	return sr->val;
 }
 
@@ -1174,7 +1507,7 @@ static double ffreq(YYSTYPE *sr)
 	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).");
+	else yyargcnterr("ffreq(x, df1, df2)");
 	return sr->val;
 }
 
@@ -1185,119 +1518,295 @@ static double finv(YYSTYPE *sr)
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  finv(p, df1, df2).");
+	else yyargcnterr("finv(p, df1, df2)");
 	return sr->val;
 }
 
-static double ksdist(YYSTYPE *sr)
+static double weibdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
-		sr->val = ks_dist((int)sr->a_data[0], sr->a_data[1]);
+		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = weib_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  ksdist(n, D).");
+	else yyargcnterr("weibdist(x, shape[, scale=1])");
 	return sr->val;
 }
 
-static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double weibfreq(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = weib_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yyargcnterr("weibfreq(x, shape[, scale=1])");
+	return sr->val;
 }
 
-static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double weibinv(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(weib_dist,sr->a_data[1], 1.0, sr->a_data[0], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(weib_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0],sr->a_data[2]);
 		}
-	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yyargcnterr("weibinv(p, shape[, scale=1])");
+	return sr->val;
 }
 
-static double kendall(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double cauchydist(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
 		}
-	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
-	return sr1->val;
+	else yyargcnterr("cauchydist(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double cauchyfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("cauchyfreq(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double cauchyinv(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(cauch_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(cauch_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargcnterr("cauchyinv(p, location[, scale=1])");
+	return sr->val;
+}
+
+static double logisdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = logis_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("logisdist(x, location[, scale=1])");
+	return sr->val;
+}
+
+static double logisfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], 1.0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = logis_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargcnterr("logisfreq(x, location[, scale=1])");
+	return sr->val;
 }
 
-static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static double logisinv(YYSTYPE *sr)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
-	if(!(dest)) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = distinv(logis_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = distinv(logis_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargcnterr("logisinv(p, location[, scale=1])");
+	return sr->val;
+}
+
+static void pearson(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 3) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
+		}
+	else yybadargerr("pearson(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
+}
+
+static void spearman(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
+		}
+	else yybadargerr("spearman(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
+}
+
+static void kendall(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
+		lval->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
+		}
+	else yybadargerr("kendall(range1; range2 [;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
+}
+
+static void regression(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
+{
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+	if(!dest && !arr) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		lval->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nregression(range1; range2; \"dest\").");
-	return sr1->val;
+	else yybadargerr("regression(range1; range2; \"dest\")");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double covar(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void _covar(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	if(!sr1 || !sr2) return;
+	lval->val = 0.0;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		lval->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, 0L, curr_data);
 		}
-	else yyargserr("Bad arguments in call to function\ncovar(range1; range2).");
-	return sr1->val;
+	else yybadargerr("covar(range1; range2)");
+	return;
 }
 
-static double ttest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ttest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         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, 0L);
+		lval->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ttest(array1; array2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double ttest2(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ttest2(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	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_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 6) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
+	if(sr1->text && sr2->text)range_array2(sr1, sr2);
+        if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count == sr1->a_count){
+		lval->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nttest2(range1; range2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ttest2(range1; range2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double utest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void utest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         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, 0L);
+		lval->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("utest2(array1; array2[;\"dest\"])");
+	if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count);
 }
 
-static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
+static void ftest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst)
 {
-	if(!sr1 || !sr2) return 0.0;
-	sr1->val = 0.0;
+	char *dest;
+	double *arr;
+
+	if(!sr1 || !sr2) return;
+	if(dst && !bNoWrite) dest = dst->text;
+	else dest = 0L;
+	if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data;
+	else arr = 0L;
+	lval->val = 0.0;	lval->type = NUM;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){
-		sr1->val = sr2->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		lval->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr);
 		}
-	else yyargserr("Bad arguments in call to function\nftest(range1; range2[;\"dest\"]).");
-	return sr1->val;
+	else yybadargerr("ftest(range1; range2[;\"dest\"])");
 }
 
 static double p_tukey(YYSTYPE *sr)
@@ -1310,7 +1819,7 @@ static double p_tukey(YYSTYPE *sr)
 	else if(sr->a_data && sr->a_count == 3){
 		sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to ptukey(q, nm, df[, nr = 1]).");
+	else yyargcnterr("ptukey(q, nm, df[, nr = 1])");
 	return sr->val;
 }
 
@@ -1324,7 +1833,7 @@ static double q_tukey(YYSTYPE *sr)
 	else if(sr->a_data && sr->a_count == 3){
 		sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
 		}
-	else yyargserr("Wrong number of arguments\nin call to qtukey(p, nm, df[, nr = 1]).");
+	else yyargcnterr("qtukey(p, nm, df[, nr = 1])");
 	return sr->val;
 }
 
@@ -1333,7 +1842,7 @@ static double fill(YYSTYPE *sr, char *dest)
 	AccRange *ar;
 	int i, r, c;
 
-	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0]) return 0.0;
+	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0] || bNoWrite) return 0.0;
 	if(ar = new AccRange(dest)) {
 		for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) {
 			curr_data->SetValue(r, c, sr->a_data[i]);
@@ -1446,7 +1955,7 @@ static double seconds(double dv)
 
 static void fdate(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -1455,7 +1964,7 @@ static void fdate(YYSTYPE *dst, YYSTYPE *src)
 
 static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -1464,7 +1973,7 @@ static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
 
 static void ftime(YYSTYPE *dst, YYSTYPE *src)
 {
-	if(!dst || !src || src->type == ARR || src->type == STR) {
+	if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) {
 		yyerror("parse error");	
 		return;
 		}
@@ -1512,6 +2021,64 @@ static void asort(YYSTYPE *dst, YYSTYPE *src)
 		}
 }
 
+static void _randarr(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
+		break;
+	default:
+		dst->a_data = randarr(src->a_data, src->a_count, &idum);
+		dst->a_count = src->a_count;
+		}
+}
+
+static void _resample(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
+		break;
+	default:
+		dst->a_data = resample(src->a_data, src->a_count, &idum);
+		dst->a_count = src->a_count;
+		}
+}
+
+static void mkarr(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char*fmt)
+{
+	AccRange *rD;
+	int i, n, r, c;
+	anyResult ares;
+
+	if(fmt || !sr2 || !sr1 || !sr1->text) yyargcnterr("mkarr(range, MD)");
+	if(!(rD = new AccRange(sr1->text)) || !(n = rD->CountItems())) {
+		yybadargerr("mkarr(range, MD)");
+		}
+	res->a_data = PushArray((double*)calloc(n, sizeof(double)));
+	for(i = 0, rD->GetFirst(&c, &r); i < n; i++) {
+		rD->GetNext(&c, &r);
+		if(curr_data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE) res->a_data[i] = ares.value;
+		else res->a_data[i] = sr2->val;
+		res->a_count = i;
+		}
+	if(rD) delete rD;
+}
+
 static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt)
 {
 	int n;
@@ -1531,9 +2098,26 @@ static double _crank(YYSTYPE *src)
 	if(!src) return tmp;
 	tmp = 0.0;
 	if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp);
+	if(src->type == RANGEARR) RangeData.rmData(src->a_data, src->a_count);
 	return tmp;
 }
 
+static void subarr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
+{
+	int i, pos2;
+
+	if(!src1->a_data) yybadargerr("subarr(array; pos1[; pos2])");
+	else {
+		if(src3) pos2 = (int)(src3->val);
+		else pos2 = src1->a_count;
+		dst->type = ARR;
+		dst->a_data = PushArray((double*)malloc(src1->a_count*sizeof(double)));
+		for(i = (int)(src2->val), dst->a_count = 0; i <= pos2 && i < src1->a_count; i++) {
+			dst->a_data[dst->a_count++] = src1->a_data[i];
+			}
+		}
+}
+
 static void ltrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
@@ -1574,14 +2158,20 @@ static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 
 static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3)
 {
-	dst->type = STR;
-	dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+	if(src3) {
+		dst->type = STR;
+		dst->text = PushString(strreplace(src1->text, src2->text, src3->text));
+		}
+	else yyargcnterr("strrepl(search; replace; haystack)");
 }
 
 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)));
+	if(src3) {
+		dst->type = STR;
+		dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val)));
+		}
+	else yyargcnterr("substr(text; pos1; pos2)");
 }
 
 static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum)
@@ -1654,13 +2244,15 @@ static void uc_word(YYSTYPE *dst, YYSTYPE *src)
 	else dst->text = 0L;
 }
 
-static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+static void exec_block(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, bool namespc)
 {
 	char *cmd = 0L;
 	int cmd_pos = 0, cmd_size, r, c;
 	AccRange *ar = 0L;
 	anyResult res, *eres;
+	YYSTYPE evsrc, evdst;
 
+	if(bNoExec) return;
 	if(!src1 || !src1->text || !src1->text[0]) return;
 	if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) {
 		if(src2 && src2->text[0] && src2->text[0]) {
@@ -1688,7 +2280,14 @@ static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 				break;
 				}
 			}while(ar->GetNext(&c, &r));
-		eres = do_formula(curr_data, cmd);
+		if(namespc) {
+			eres = do_formula(curr_data, cmd);
+			}
+		else {
+			memset(&evsrc, 0, sizeof(YYSTYPE));	memset(&evdst, 0, sizeof(YYSTYPE));
+			evsrc.text = cmd;			eval(&evdst, &evsrc);
+			eres = &line_res;
+			}
 		switch(eres->type) {
 		case ET_BOOL:
 			dst->type = BOOLVAL;	dst->val = eres->value;
@@ -1707,6 +2306,17 @@ static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
 	if(cmd) free(cmd);	if(ar) delete ar;
 }
 
+static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	exec_block(dst, src1, src2, true);
+}
+
+static void call(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	exec_block(dst, src1, src2, false);
+}
+
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -1798,6 +2408,13 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
+	INIT_SYM(YYFNC3, "mkarr", mkarr),
+	INIT_SYM(YYFNC, "randarr", _randarr),		INIT_SYM(YYFNC, "resample", _resample),
+	INIT_SYM(AFNCT, "weibdist", weibdist),		INIT_SYM(AFNCT, "weibfreq", weibfreq),
+	INIT_SYM(AFNCT, "weibinv", weibinv),		INIT_SYM(AFNCT, "cauchydist", cauchydist),
+	INIT_SYM(AFNCT, "cauchyfreq", cauchyfreq),	INIT_SYM(AFNCT, "cauchyinv", cauchyinv),
+	INIT_SYM(AFNCT, "logisdist", logisdist),	INIT_SYM(AFNCT, "logisfreq", logisfreq),
+	INIT_SYM(AFNCT, "logisinv", logisinv),		INIT_SYM(YYFNC2, "call", call),
 	INIT_SYM(AFNCT, "ptukey", p_tukey),		INIT_SYM(AFNCT, "qtukey", q_tukey),
 	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
 	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
@@ -1815,12 +2432,12 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
 	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
 	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),
-	INIT_SYM(FUNC2, "covar", covar),		INIT_SYM(YYFNC2, "exec", exec),
-	INIT_SYM(FUNC3, "utest", utest),		INIT_SYM(FUNC2, "ttest2", ttest2),
-	INIT_SYM(FUNC3, "ttest", ttest),		INIT_SYM(FUNC3, "ftest", ftest),
+	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(YYFNC3, "pearson", pearson),
+	INIT_SYM(YYFNC3, "spearman", spearman),		INIT_SYM(YYFNC3, "kendall", kendall),		
+	INIT_SYM(YYFNC3, "correl", pearson),		INIT_SYM(YYFNC3, "regression", regression),
+	INIT_SYM(YYFNC2, "covar", _covar),		INIT_SYM(YYFNC2, "exec", exec),
+	INIT_SYM(YYFNC3, "utest", utest),		INIT_SYM(YYFNC3, "ttest2", ttest2),
+	INIT_SYM(YYFNC3, "ttest", ttest),		INIT_SYM(YYFNC3, "ftest", ftest),
 	INIT_SYM(AFNCT, "variance", variance),		INIT_SYM(AFNCT, "stdev", stdev),
 	INIT_SYM(AFNCT, "sterr", sterr),		INIT_SYM(AFNCT, "min", min),
 	INIT_SYM(AFNCT, "max", max),			INIT_SYM(AFNCT, "count", count),
@@ -1834,12 +2451,12 @@ void InitArithFuncs(DataObj *d)
 	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, "ffreq", ffreq),		INIT_SYM(AFNCT, "ksdist", ksdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),		INIT_SYM(YYFNC3, "subarr", subarr),
 	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),
 	INIT_SYM(AFNCT, "binomdist",binomdist),		INIT_SYM(AFNCT, "binomfreq",binomfreq),
-	INIT_SYM(AFNCT, "normdist", normdist),
+	INIT_SYM(AFNCT, "normdist", normdist),		INIT_SYM(AFNCT, "average", mean),
 	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),
@@ -1935,6 +2552,14 @@ getsym (unsigned int h_name, unsigned int h2_name, char *sym_name)
 static int
 push(YYSTYPE *res, YYSTYPE *val)
 {
+	double *tmparr;
+
+	if(res->type == RANGEARR || res->text) {
+		if((tmparr = res->a_data) && (res->a_data = PushArray((double*)malloc((res->a_count+1)*sizeof(double))))){
+			memcpy(res->a_data, tmparr, res->a_count * sizeof(double));
+			res->type = ARR;	res->text = 0L;
+			}
+		}
 	if(val->a_data) {
 		if(!(res->a_data)) {
 			if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
@@ -1966,29 +2591,10 @@ push(YYSTYPE *res, YYSTYPE *val)
 }
 
 static int
-range_array(YYSTYPE * res, char *range)
+range_array(YYSTYPE *res, char *range)
 {
-	AccRange *r;
-	int row, col;
-	anyResult ares;
-
-	if(!range || !range[0] || !(r = new AccRange(range))) return 0;
-	if(!r->GetFirst(&col, &row) || !(res->a_data =  PushArray((double*)malloc(r->CountItems() * sizeof(double))))) {
-		delete(r);
-		return 0;
-		}
-	parse_level++;
-	for(res->a_count = 0; r->GetNext(&col, &row); ) {
-		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
-			switch(ares.type) {
-			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
-				res->a_data[res->a_count++] = ares.value;
-				break;
-				}
-			}
-		}
-	parse_level--;
-	delete(r);
+	RangeData.GetData(range, &res->a_data, &res->a_count, &res->text); 
+	res->val = 0.0;		res->type = RANGEARR;
 	return 1;
 }
 
@@ -2021,7 +2627,7 @@ range_array2(YYSTYPE *res1, YYSTYPE *res2)
 			res2->a_data[res2->a_count++] = ares2.value;
 			}
 		}
-	parse_level--;
+	parse_level--;	res1->type = res2->type = ARR;
 	delete(r1);	delete(r2);
 	return 1;
 }
@@ -2218,7 +2824,13 @@ static char *copy_block()
  			if(src[i] == last[level]) {
 				if(level) level--;
 				else {
-					res[j-1] = ';';	res[j] = 0;	buff_pos += j;
+					if(res[j-2] == ';'){
+						res[j-1] = 0;
+						}
+					else {
+						res[j-1] = ';';		res[j] = 0;	
+						}
+					buff_pos += j;
 					return res;
 					}
 				}
@@ -2234,6 +2846,7 @@ static char *copy_block()
 				}
 			}
 		}
+	if(res[j-1] == ';') j--;
 	res[j] = ';';	res[j+1] = 0;		buff_pos += j;
 	return res;
 }
@@ -2247,7 +2860,7 @@ static double for_loop(char *block1, char *block2)
 	YYSTYPE yyres, yysrc;
 	symrec *var;
 
-	if(!block1 || !block1[0]) return 0.0;
+	if(!block1 || !block1[0] || bNoExec) return 0.0;
 	bb1 = bb2 = bb3 = 0L;		parse_level++;
 	cb1 = (int)strlen(block1);
 	last_buffer = buffer;		last_buff_pos = buff_pos;
@@ -2371,9 +2984,8 @@ static int yylex()
 				tmp_txt[i++] = (char)c; 
 				}
 			tmp_txt[i] = 0;
-			yylval.text = PushString(tmp_txt);
-			range_array(&yylval, yylval.text);
-			yylval.val = 0.0;
+			RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text); 
+			yylval.val = 0.0; 
 			return yylval.type = RANGEARR;
 			}
 		tmp_txt[i] = 0;
@@ -2459,6 +3071,9 @@ static int yylex()
 			else syntax_level->last_tok = 0;
 			}
 		break;
+	case ',':
+		if(syntax_level && syntax_level->last_tok == '(') return LSEP;
+		break;
 	case '*':
 		if(buffer[buff_pos] == '=') tok = MULEQ;
 		break;
@@ -2498,6 +3113,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	int length, parse_res, res_mode = 0;
 
 	if(x1 < x2) step = fabs(step);
+	else if(x1 == x2) return false;
 	else step = -fabs(step);
 	if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT))))
 		return false;
@@ -2670,9 +3286,9 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
 				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:
-			case YYFNC2:	case YYFNC3:
+			case FNCT:	case FUNC1:	case AFNCT:	case SFNCT:
+			case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:	case YYFNC2:
+			case YYFNC3:
 				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case COLC:
@@ -2681,12 +3297,18 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
 			case PSEP:
 				res[pos++] = ';';
 				break;
+			case LSEP:
+				res[pos++] = ',';
+				break;
 			case CLVAL:
 				res[pos++] = '$';	res[pos++] = '$';
 				break;
 			case CLAUSE:
 				pos += rlp_strcpy(res+pos, length2-pos, " where ");
 				break;
+			case DIM:
+				pos += rlp_strcpy(res+pos, length2-pos, "dim ");
+				break;
 			case VAR:
 				curr_sym->InitSS();
 				if(curr_sym->col >= 0 && curr_sym->row >= 0) {
@@ -3007,3 +3629,5 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 
 
 
+
+
diff --git a/reports.cpp b/reports.cpp
index 42e8b9c..dcb9388 100755
--- a/reports.cpp
+++ b/reports.cpp
@@ -103,7 +103,7 @@ static void rep_DrawText(GraphObj *parent, double x, double y, bool moveable, in
 {
 	char *txt_obj;
 
-	if(txt_obj = mk_label(x, y,	false, align, td, text)) {
+	if(txt_obj = mk_label(x, y,	moveable, align, td, text)) {
 		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
 		free(txt_obj);
 		}
@@ -158,7 +158,7 @@ static int dbl_to_str2(char *dest, int size, char* fmt, double val1, double val2
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create general information on report page
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_header(Page *page, char* desc)
+static void mk_header(Page *page, char* desc, DataObj *data)
 {
 	time_t ti = time(0L);
 	char label[80];
@@ -180,6 +180,11 @@ static void mk_header(Page *page, char* desc)
 	cb = rlp_strcpy(label, 80, "RLPlot ");		cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
 	rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
 		false, TXA_HRIGHT, &txtdef1, label);
+	if(data && data->Command(CMD_GETFILENAME, TmpTxt, 0L)) {
+		rpos = page->GetSize(SIZE_GRECT_LEFT) + txtdef1.fSize*5.0;
+		rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
+			false, TXA_HLEFT, &txtdef1, TmpTxt);
+		}
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -273,12 +278,15 @@ static double mk_median_report(GraphObj *parent, double x, double y, double *da,
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create report table for anova ...
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_table(GraphObj *parent, double x, double y, int type, double **dda)
+static double mk_table(GraphObj *parent, double x, double y, int type, double **dda)
 {
 	char *cheaders[] = {"<i>df</i>", "<i>SS</i>", "<i>MS</i>", "<i>F</i>", "<i>P</i>"};
-	char *rheaders[] = {"Source of variation", type == 2 ? (char*)"Explained by regression":
+	char *rheaders1[] = {"Source of variation", type == 2 ? (char*)"Explained by regression":
 		(char*)"Among groups", type == 2 ? (char*)"Unexplained":(char*)"Within groups", "Total"};
-	char *cfmt[8];
+	char *rheaders2[] = {"Source of variation", "Between rows", "Between columns", "Interaction",
+		"Within subgroups (error)", "Total"};
+	char *rheaders3[] = {"Source of variation", "Between columns", "Between rows", "Error", "Total"};
+	char *cfmt[8], **rheaders;
 	int i, j, nl, nc[8];
 	double posc[8], cinc;
 
@@ -287,19 +295,38 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 #else
 	cinc = txtdef1.fSize *1.3;
 #endif
+	cfmt[0] = "%.0lf";		cfmt[3] = "%0.3lf";			cfmt[4] = "%0.4lf";
 	switch(type) {
 	case 1:	case 2:
+		rheaders = rheaders1;
 		nl = 3;	nc[0] = 5;	nc[1] = 3;	nc[2] = 2;
 		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";
+		posc[4] = posc[3] + cinc*6.0;
+		cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));	
+		cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2])-3.0));
+		break;
+	case 3:
+		rheaders = rheaders2;
+		nl = 5;	nc[0] = nc[1] = nc[2] = 5;	nc[3] = 3;	nc[4] = 2;
+		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[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";
 		break;
-	default: return;
+	case 4:
+		rheaders = rheaders3;
+		nl = 4;	nc[0] = nc[1] = 5;	nc[2] = 3;	nc[3] = 2;
+		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[1] = GetNumFormat(floor(log10(dda[3][1])-4.0));	
+		cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2]+dda[2][2])-4.0));
+		break;
+	default: return y;
 		}
-	if(type == 1 || type == 2) {
+	if(type == 1 || type == 2 || type == 3 || type == 4) {
 		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[0]);
 		for(i = 0; i < 5; i++) {
 			rep_DrawText(parent, posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i]);
@@ -323,12 +350,13 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 			mk_hr(parent, x, posc[4], y + linsp1);		y += linsp2;
 			}
 		}
+	return y;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // 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, 
+static char* mk_boxplot(int style, 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;
@@ -342,11 +370,20 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 	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);
+		if(style == 1) {
+			add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
+			add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+			add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+			add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
+			add_dbl_to_buff(&res, &pos, &csize,y[i], true);
+			}
+		else {
+			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\nName= \"", 17);
 		add_to_buff(&res, &pos, &csize, b_nam, 0);
 		add_to_buff(&res, &pos, &csize, "\"\n", 2);
@@ -355,11 +392,20 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 	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);
+		if(style == 1) {
+			add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+			add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+			add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+			add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
+			add_dbl_to_buff(&res, &pos, &csize,y[i], true);
+			}
+		else {
+			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);
@@ -384,15 +430,24 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 		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);
+		if(style == 1) {
+			add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+			add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+			add_to_buff(&res, &pos, &csize, "\nDist=", 6);
+			add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
+			add_to_buff(&res, &pos, &csize, " 0", 2);
+			}
+		else {
+			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_int_to_buff(&res, &pos, &csize, style == 1 ? (TXA_HLEFT | TXA_VCENTER):(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);
@@ -437,11 +492,11 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create a scatterplot for a report
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_nam, char *x_desc, char *y_desc)
+static char* mk_scatt(int style, 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;
-	double size, linew, tmp;
+	double size, linew, tmp, val;
 
 	if(!(res = (char*)malloc(csize = 2000)))return 0L;
 	if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
@@ -464,7 +519,9 @@ static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_
 			else tmp = 0.0;
 			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_to_buff(&res, &pos, &csize, "=ErrorBar]\nType=", 16);
+			add_int_to_buff(&res, &pos, &csize, style & 0x10 ? 3 : 0, true, 0);
+			add_to_buff(&res, &pos, &csize, "\nPos=", 5);
 			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);
@@ -477,15 +534,29 @@ static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_
 			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);
+			if(style & 0x10) {
+				val = x ? x[i] : (double)(i+1);
+				if(dBounds.Xmin > (val-tmp)) dBounds.Xmin = val-tmp;
+				if(dBounds.Xmax < (val+tmp)) dBounds.Xmax = val+tmp;
+				add_dbl_to_buff(&res, &pos, &csize, val+tmp, true);
+				add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+				add_to_buff(&res, &pos, &csize, "\nDist=", 6);
+				add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
+				add_to_buff(&res, &pos, &csize, " 0", 2);
+				}
+			else {
+				if(dBounds.Ymin > (y[i]-tmp)) dBounds.Ymin = y[i]-tmp;
+				if(dBounds.Ymax < (y[i]+tmp)) dBounds.Ymax = y[i]+tmp;
+				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_int_to_buff(&res, &pos, &csize, (style & 0x10)?(TXA_HLEFT | TXA_VCENTER) : (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);
@@ -534,30 +605,236 @@ static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_
 	return res;
 }
 
+static double contrasts_level = 95.0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a contrasts report for one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_contrasts(GraphObj* par, int type, double dx, double dy, double *y, double *ss, int *ny, int n, 
+	char **names, double ci, double msw, double msdf)
+{
+	double tmp, tkd, pcorr, cx[10], *raw;
+	int i, j, k, l, c, df, *co, nco, cb;
+	char ctext[5], **contrasts;
+	char *headings[] = {"<i>Groups</i>", "<i>Mean</i>", "<i>Std. Dev.</i>", "<i>N</i>",
+		"<i>Contrasts</i><sup>1)</sup>"};
+
+	if(!par || !y || !ss || !ny || n < 2) return;
+	cx[0] = txtdef1.fSize*5.0;		cx[1] = cx[0] + linsp1*5.0;
+	cx[2] = cx[1] + linsp1*5.0;		cx[3] = cx[2] + linsp1*5.0;
+	cx[4] = cx[3] + linsp1*4.0;		cx[5] = cx[4] + linsp1*3.0;
+	cx[6] = cx[5] + linsp1*4.0;
+
+	rep_DrawText(par, dx, dy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
+	for(i = 0, dy += linsp2; i < 5; i++) {				//column headers
+		c = (i == 4) ? TXA_HLEFT : TXA_HRIGHT;
+		rep_DrawText(par, cx[i+1], dy, false, c, &txtdef1, headings[i]);
+		}
+	mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy +linsp1);
+	if(type == 1 || type == 2) {	
+		if(!(co = (int*)malloc(n*sizeof(int)))) return;
+		if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
+		rlp_strcpy(ctext, 5, ", a");
+		for(i = df = 0, nco = n; i < n; i++) {
+			if(ny[i] > 0) df += (ny[i]-1);
+			co[i] = i;
+			contrasts[i] = (char*)calloc(50, sizeof(char));
+			}
+		tkd = qtukey(1.0-ci, 1.0, (double) n, (double)df, 1, 0);
+		for(i = 0; nco; ) {
+			for(j = 0; j < n; j++) {
+				switch(type) {
+					case 1:					//Tukey-Kramer
+						tmp = tkd * sqrt((msw*(1.0/((double)ny[j]) + 1.0/((double)ny[co[i]])))/2.0);
+						break;
+					case 2:					//Tukey's HSD
+						tmp = tkd * sqrt(msw/(ny[j] <= ny[co[i]] ? ny[j] : ny[co[i]]));
+						break;
+					}
+				if(fabs(y[j]-y[co[i]]) < tmp) {
+					cb = (int)strlen(contrasts[j]);
+					rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
+					}
+				}
+			for(j = nco = 0; j < n; j++) {
+				if(!(contrasts[j][0])) co[nco++] = j;
+				}
+			ctext[2]++;
+			}
+		}
+	else if(type == 10) {
+		if(!(co = (int*)malloc(n*sizeof(int)))) return;
+		if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
+		if(!(raw = (double*)malloc((n*n-1)*sizeof(double))))return;
+		rlp_strcpy(ctext, 5, ", a");
+		for(i = df = 0, nco = n; i < n; i++) {
+			if(ny[i] > 0) df += (ny[i]-1);
+			co[i] = i;
+			contrasts[i] = (char*)calloc(50, sizeof(char));
+			}
+		for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
+			raw[k++] = t_dist(fabs(0.5*(y[i]-y[j])/sqrt(msw/(ny[i]+ny[j]))), msdf, 0.0);
+			}
+		SortArray(k, raw);
+		for(i = 0; nco; ) {
+			for(j = 0; j < n; j++) {
+				tmp = t_dist(fabs(0.5*(y[j]-y[co[i]])/sqrt(msw/(ny[j]+ny[co[i]]))), msdf, 0.0);
+				for(l = 0; l < k && tmp > raw[l]; l++);
+				switch(type) {
+				case 10:					//Dunn Sidak
+					pcorr = 1.0 - pow((1.0 - ci), 1.0 /(double(k-l)));
+					break;
+					}
+				if(tmp > pcorr || j == co[i]) {
+					cb = (int)strlen(contrasts[j]);
+					rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
+					}
+				}
+			for(j = nco = 0; j < n; j++) {
+				if(!(contrasts[j][0])) co[nco++] = j;
+				}
+			ctext[2]++;
+			}
+		free(raw);
+		}
+	else return;
+
+	for(i = 0, dy += linsp2; i < n; i++, dy +=linsp1) {
+		if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+		else tmp = 0.0;
+		rep_DrawText(par, cx[1], dy, false, TXA_HRIGHT, &txtdef1, names[i]);
+		dbl_to_str1(TmpTxt, 20, "%g", y[i]);
+		rep_DrawText(par, cx[2], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+		if(tmp > 0.0) {
+			dbl_to_str1(TmpTxt, 20, "%g", tmp);
+			rep_DrawText(par, cx[3], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+			}
+		if(ny[i] >1) {
+			dbl_to_str1(TmpTxt, 20, "%.0lf", (double)ny[i]);
+			rep_DrawText(par, cx[4], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+			}
+		rep_DrawText(par, cx[5], dy, false, TXA_HLEFT, &txtdef1, contrasts[i]+2);
+		}
+	mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy+txtdef1.fSize*0.2);
+	cb = dbl_to_str1(TmpTxt, 200, "<sup>1)</sup> Groups not sharing the same letter are different "
+		"on the %g%% level ", (1.0-ci)*100.0);
+	switch (type) {
+	case 1:						//Tukey-Kramer
+		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, "(Tukey-Kramer method)");
+		break;
+	case 2:						//Tukey's HSD
+		rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false, 
+			TXA_HLEFT, &txtdef1, "(Tukey's honest significant difference)");
+		break;
+	case 10:					//Dunn-Sidak
+		rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false, 
+			TXA_HLEFT, &txtdef1, "(sequential Dunn-Sidak method)");
+		break;
+		}
+	rep_DrawText(par, cx[0], dy += txtdef2.fSize , false, TXA_HLEFT, &txtdef1, TmpTxt);
+	for(i = 0; i < n; i++) free(contrasts[i]);
+	free(co);		free(contrasts);
+	return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a homogeneity of variances report for one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_v_homogeneity(GraphObj* par, DataObj *data, double *dx, double *dy, double *y, double *ss,
+	int *ny, int n, double **vals)
+{
+	int i;
+	double tmp, *sd, f1, f2, p1, p2;
+	char *txt_obj;
+	scaleINFO scale = {{0.0, 0.8}, {0.0, 0.8}, {0.0, 0.8}};
+	Graph *graph;
+
+	if(!par || !y || !ss || !ny || n < 2) return;
+	if(!(sd = (double*)malloc(n*sizeof(double)))) return;
+	rep_DrawText(par, *dx, *dy, false, TXA_HLEFT, &txtdef1, "<b>Homogeneity of Variances:</b>");
+	for(i = 0; i < n; i++) {
+		if(ny[i] > 1) sd[i] = sqrt(ss[i]/(ny[i]-1));
+		else sd[i] = 0.0;
+		if(i) {
+			if(dBounds.Xmax < y[i]) dBounds.Xmax = y[i];
+			if(dBounds.Xmin > y[i]) dBounds.Xmin = y[i];
+			if(dBounds.Ymax < sd[i]) dBounds.Ymax = sd[i];
+			if(dBounds.Ymin > sd[i]) dBounds.Ymin = sd[i];
+			}
+		else {
+			dBounds.Xmax = dBounds.Xmin = y[0];
+			dBounds.Ymax = dBounds.Ymin = sd[0];
+			}
+		}
+	if((graph = new Graph(par, data, 0L, 0)) && (txt_obj = mk_scatt(0, y, sd, 0L, ny, n, 
+		"Variables", "Means", "Std.Dev."))){
+		graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM)*0.8;
+		graph->GRect.Ymax *= 0.8;
+		graph->DRect.Xmin *= 0.8;				graph->DRect.Ymax *= 0.8;				
+		graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+		scale.sx.fx = par->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0 - graph->GRect.Xmax*0.8 + graph->GRect.Xmin*0.8;		
+		scale.sy.fx = *dy;
+		OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		graph->Command(CMD_SCALE, &scale, 0L);
+		if(!(par->Command(CMD_DROP_GRAPH, graph, 0L))) delete graph;
+		else graph->moveable = 0;
+		}
+	if(bartlett(n, ny, ss, &tmp)) {
+		rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Bartlett's test:");
+		i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi<sup>2</sup> = %.2lf, ", tmp);
+		tmp = chi_dist(tmp, n-1, 0);
+		dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", tmp);
+		rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		}
+	if(levene(1, n, ny, y, vals, &f1, &p1) && levene(2, n, ny, y, vals, &f2, &p2) ) {
+		rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Levene's test:");
+		i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using means: F = %.2lf, ", f1);
+		dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p1);
+		rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using medians: F = %.2lf, ", f2);
+		dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p2);
+		rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		}
+	free(sd);
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // one way anova
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char *AnovaDlg_Tmpl =
-	"1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
-	"2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
-	"3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
-	"10,20,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+	"1,+,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,158,25,45,12\n"
+	".,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"10,+,152,ISPARENT | CHECKED,SHEET,1,5,10,140,90\n"
+	".,20,100,ISPARENT,SHEET,2,5,10,140,90\n"
 	"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
-	"152,153,,ISPARENT | CHECKED,GROUPBOX,2,12,30,128,45\n"
-	"153,154,,,LTEXT,0,25,35,60,8\n"
-	"154,155,,,RANGEINPUT,0,25,45,100,10\n"
-	"155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
-	"156,,,LASTOBJ,PUSHBUTTON,-9,60,57,35,12";
+	"100,104,,ISRADIO,CHECKBOX,8,20,25,100,9\n"
+	"104,+,,,LTEXT,4,15,37,100,9\n"
+	".,.,,ISRADIO,CHECKBOX,5,20,47,100,9\n"
+	".,.,,ISRADIO,CHECKBOX,9,20,57,100,9\n"
+	".,110,,ISRADIO,CHECKBOX,10,20,67,100,9\n"
+	"110,+,,,LTEXT,7,20,85,55,9\n"
+	".,.,,,EDVAL1,6,80,85,25,10\n"
+	".,,,,LTEXT,-10,107,85,10,9\n"
+	"152,+,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,65\n"
+	".,.,,,LTEXT,0,25,45,60,8\n"
+	".,.,,,RANGEINPUT,0,25,55,100,10\n"
+	".,.,0,,PUSHBUTTON,-8,95,70,30,12\n"
+	".,,,LASTOBJ,PUSHBUTTON,-9,60,70,35,12";
 
 void rep_anova(GraphObj *parent, DataObj *data)
 {
 	TabSHEET tab1 = {0, 45, 10, "Anova Input"};
+	TabSHEET tab2 = {45, 75, 10, "Tests"};
 	DlgInfo *AnovaDlg;
-	void *dyndata[] = {(void*)&tab1, (void*)" select one range for every variable "};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)" select one range for every variable ",
+		(void*)"Contrasts:", (void*)" Tukey-Kramer method", (void*)&contrasts_level, (void*)"significance level:",
+		(void*)" Homogeneity of Variances", (void*)" Tukey's honest sig. difference", (void*)" Dunn-Sidak"};
 	DlgRoot *Dlg;
 	void *hDlg;
-	double **cols = 0L, tmp, *csums=0L, mtot, *css=0L, ssa, ssw, sst;
-	double **res_tab = 0L;
+	double **cols = 0L, *csums=0L, mtot, *css=0L, cx, cy;
+	double **res_tab = 0L, ci;
 	int i, j, n, c, r, res, nc, ntot, currYR = 0, maxYR=0, ny, *ncols = 0L;;
 	bool bContinue = false, updateYR = true;
 	anyResult ares;
@@ -577,7 +854,7 @@ void rep_anova(GraphObj *parent, DataObj *data)
 	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
 	if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
 	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
-	hDlg = CreateDlgWnd("Single-Classification Anova", 50, 50, 420, 200, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Single-Classification Anova", 50, 50, 420, 240, Dlg, 0x0L);
 	do {
 		if(updateYR) {
 			if(currYR >0) Dlg->ShowItem(156, true);
@@ -612,10 +889,11 @@ void rep_anova(GraphObj *parent, DataObj *data)
 		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))
 		&& (cols = (double**)calloc(maxYR+1, sizeof(double*)))
 		&& (names = (char**)calloc(maxYR+1, sizeof(char*)))
-		&& (ncols = (int*)calloc(maxYR+1, sizeof(int)))
-		&& (csums = (double*)calloc(maxYR+1, sizeof(double)))
-		&& (css = (double*)calloc(maxYR+1, sizeof(double)))) {
+		&& (ncols = (int*)calloc(maxYR+1, sizeof(int)))) {
 		rep_init();		if(rD) delete rD;		rD = 0L;
+		if(Dlg->GetValue(111, &ci)) {
+			contrasts_level = ci;		ci = 1.0-(ci/100.0);
+			}
 		dBounds.Ymin = HUGE_VAL;		dBounds.Ymax = -HUGE_VAL;
 		// get data into two dimensional array
 		for(nc = maxYR+1, i = ntot = 0, mtot = 0.0; i < nc; i++) {
@@ -625,11 +903,10 @@ void rep_anova(GraphObj *parent, DataObj *data)
 					if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
 						if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
 						if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
-						cols[i][n] = ares.value;		csums[i] += cols[i][n++];
+						cols[i][n++] = ares.value;
 						}
 					}
-				ncols[i] = n;		ntot += n;		mtot += csums[i];
-				if(ncols[i]) csums[i] /= ((double)ncols[i]);
+				ncols[i] = n;		ntot += n;		//mtot += csums[i];
 				delete(rD);			rD = 0L;
 				}
 			if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
@@ -652,49 +929,711 @@ void rep_anova(GraphObj *parent, DataObj *data)
 #endif
 				}
 			}
-		dBounds.Xmin = 0.5;				dBounds.Xmax = ((double)nc)+0.5;
-		if(ntot) mtot /= ((double)ntot);
-		for(i = 0; i < nc; i++) {
-			for(j = 0, css[i] = 0.0; j < ncols[i]; j++) {
-				tmp = cols[i][j] - csums[i];	css[i] += (tmp*tmp);
+
+		if(do_anova1(nc, ncols, cols, res_tab, &mtot, &csums, &css)){
+			dBounds.Xmin = 0.5;				dBounds.Xmax = ((double)nc)+0.5;
+			page = new Page(parent, data);
+			mk_header(page, "<b>Single-Classification ANOVA</b>", data);
+			if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+					if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
+						for(i = 0; i < nc; i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(names[i]);
+						}
+					}
+				free(txt_obj);								graph->moveable = 0;
+				graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
+				graph->GRect.Ymin += (txtdef1.fSize*10.0);	graph->GRect.Ymax += (txtdef1.fSize*10.0);
+				page->Command(CMD_DROP_GRAPH, graph, 0L);
+				}
+			cx = graph->GRect.Xmin;		cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+			rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+			cy = mk_table(page, cx, cy+txtdef2.fSize, 1, res_tab)+txtdef2.fSize;
+			if(Dlg->GetCheck(100)) mk_v_homogeneity(page, data, &cx, &cy, csums, css, ncols, nc, cols);
+			else if(Dlg->GetCheck(105)) mk_contrasts(page, 1, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+			else if(Dlg->GetCheck(106)) mk_contrasts(page, 2, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+			else if(Dlg->GetCheck(107)) mk_contrasts(page, 10, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+			if(ntot > (nc<<1) && nc >1 && parent->Command(CMD_DROP_GRAPH, page, 0L));
+			else {
+				delete page;
+				InfoBox("No or insufficient\ndata for ANOVA\n");
+				}
+			}
+		for(i = 0; i < nc; i++){
+			if(cols[i]) free(cols[i]);		if(names[i]) free(names[i]);
+			}
+		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+		free(cols);			free(ncols);			free(names);
+		free(res_tab);		if(css)free(css);		if(csums)free(csums);
+		}
+	if(rD) delete rD;		CloseDlgWnd(hDlg);
+	delete Dlg;				free(AnovaDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Parametric two way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TwAnov_DlgTmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,+,,,LTEXT,2,10,30,60,8\n"
+	".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+	".,,,LASTOBJ,CHECKBOX,3,20,60,100,9";
+
+void rep_twanova(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 40, 10, "Input Data"};
+	DlgInfo *TwAnovDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
+		(void*)" column/row headers present"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
+	bool bContinue = false;
+	char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
+	double gm, ssc, ssr, sse, tmp, cx, cy, dmin, dmax;
+	double **vals = 0L, *cs = 0L, *rs = 0L, **res_tab = 0L, *c_ss, *r_ss, *c_m, *r_m, *abc;
+	RECT rec;
+	scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
+	AccRange *rD =0L, *rDesc;
+	anyResult ares;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(TwAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+	else {
+		data->ValueRec(&rec);
+		rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+		}
+	if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
+	hDlg = CreateDlgWnd("Two-Way Anova", 50, 50, 420, 220, 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(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
+				&& (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
+				nc = rec.right-rec.left+1;				nr = rec.bottom-rec.top+1;
+				nvc = (int*)calloc(nc, sizeof(int));	nvr = (int*)calloc(nr, sizeof(int));
+				dmin = HUGE_VAL;						dmax = -HUGE_VAL;
+				if(Dlg->GetCheck(102)) hr = hc = 1;
+				else hr = hc = 0;
+				for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
+				for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
+					if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
+						nvc[c-rec.left]++;				nvr[r-rec.top]++;
+						if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
+						if(ares.value > dmax) dmax = ares.value;
+						if(ares.value < dmin) dmin = ares.value;
+						}
+					}
+				while(!nvc[nc-1] && nc > 1) nc--;
+				while(!nvr[nr-1] && nr > 1) nr--;
+				for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
+				for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
+				for( ; nvr[hr] < mr && hr < nr; hr++);
+				for( ; nvc[hc] < mc && hc < nc; hc++);
+				for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
+				for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
+				for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
+				for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
+				if(res < 0 || mr < 2 || mc < 2) {
+					InfoBox("There are missing data!");
+					for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+					free(vals);			free(nvr);			free(nvc);
+					nvr = nvc = 0L;		vals = 0L;
+					bContinue = true;
+					}
+				delete rD;
+				}
+			break;
+		default:
+			nr = nc = 0;		break;
+			}
+		}while (res < 0);
+	if(res == 1 && (vals) && (cs = (double*)calloc(nc, sizeof(double))) 
+		&& (rs = (double*)calloc(nr, sizeof(double)))
+		&& (c_ss = (double*)calloc(nc, sizeof(double)))
+		&& (r_ss = (double*)calloc(nr, sizeof(double)))
+		&& (c_m = (double*)calloc(nc, sizeof(double)))
+		&& (r_m = (double*)calloc(nr, sizeof(double)))
+		&& (abc = (double*)calloc(nr > nc ? nr : nc, sizeof(double)))
+		&& (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
+		&& (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
+		&& (res_tab = (double**)calloc(4, sizeof(double*)))
+		&& (res_tab[0] = (double*)calloc(5, sizeof(double)))
+		&& (res_tab[1] = (double*)calloc(5, sizeof(double)))
+		&& (res_tab[2] = (double*)calloc(5, sizeof(double)))
+		&& (res_tab[3] = (double*)calloc(5, sizeof(double)))){
+		//get column and row descriptors
+		for(c = hc; c < nc; c++) {
+			if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
+				cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
+				delete rDesc;
 				}
 			}
-		for(i = 0, ssa = ssw = sst = 0.0;  i < nc; i++) {
-			tmp =(csums[i] - mtot);		ssa += (tmp*tmp) * ((double)ncols[i]);
-			ssw += css[i];
+		for(r = hr; r < nr; r++) {
+			if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
+				rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
+				delete rDesc;
+				}
+			}
+		//grand mean
+		for(c = hc, gm = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
+			gm += vals[r][c];	cs[c] += vals[r][c];	rs[r] += vals[r][c];
+			}
+		gm /= ((double)((nc-hc)*(nr-hr)));
+		//anova stats
+		for(c = hc; c < nc; c++) cs[c] /= ((double)nvc[c]);
+		for(c = hc, ssc = 0.0; c < nc; c++) ssc += ((tmp = cs[c]-gm)*tmp); 
+		for(r = hr; r < nr; r++) rs[r] /= ((double)nvr[r]);
+		for(r = hr, ssr = 0.0; r < nr; r++) ssr += ((tmp = rs[r]-gm)*tmp);
+		ssc *= ((double)(nr-hr));		ssr *= ((double)(nc-hc));
+		for(c = hc, sse = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
+			sse += ((tmp = vals[r][c]-cs[c]-rs[r]+gm)*tmp);
 			}
-		sst = ssa + ssw;
-		res_tab[0][0] = nc - 1;				res_tab[1][0] = ntot - nc;
-		res_tab[2][0] = ntot -1;			res_tab[0][1] = ssa;
-		res_tab[1][1] = ssw;				res_tab[2][1] = sst;
-		res_tab[0][2] = ssa/res_tab[0][0];	res_tab[1][2] = ssw/res_tab[1][0];
-		res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
-		res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
+		for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
+			c_m[c-hc] += vals[r][c];		r_m[r-hr] += vals[r][c];
+			}
+		for(c = hc; c < nc; c++) c_m[c-hc] /= ((double)(nvc[c]));
+		for(r = hr; r < nr; r++) r_m[r-hr] /= ((double)(nvr[r]));
+		for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
+			c_ss[c-hc] += ((tmp = vals[r][c]-c_m[c-hc])*tmp);
+			r_ss[r-hr] += ((tmp = vals[r][c]-r_m[r-hr])*tmp);
+			}
+		//prepare table for report
+		res_tab[0][0] = (double)(nc-hc-1);			res_tab[1][0] = (double)(nr-hr-1);
+		res_tab[2][0] = res_tab[0][0] * res_tab[1][0];
+		res_tab[3][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0];
+		res_tab[0][1] = ssc;						res_tab[0][2] = ssc/res_tab[0][0];
+		res_tab[1][1] = ssr;						res_tab[1][2] = ssr/res_tab[1][0];
+		res_tab[2][1] = sse;						res_tab[2][2] = sse/res_tab[2][0];
+		res_tab[3][1] = ssc + ssr + sse;
+		res_tab[0][3] = res_tab[0][2] / res_tab[2][2];
+		res_tab[1][3] = res_tab[1][2] / res_tab[2][2];
+		res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[2][0]);
+		res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[2][0]);
+		rep_init();
 		page = new Page(parent, data);
-		mk_header(page, "<b>Single-Classification ANOVA</b>");
-		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
+		mk_header(page, "<b>Two-Way ANOVA</b>", data);
+		cx = txtdef1.fSize*5.0;		cy = txtdef1.fSize*10.0;
+		dBounds.Xmin = 0.5;			dBounds.Xmax = ((double)(nc-hc))+0.5;
+		dBounds.Ymin = dmin;		dBounds.Ymax = dmax;
+		//plot column results
+		if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, c_m, c_ss, nvc+hc, nc-hc, "Mean", "Columns", "Means <u>+</u> S.D."))){
 			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
 			if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
 				if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
-					for(i = 0; i < nc; i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(names[i]);
+					for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
 					}
 				}
 			free(txt_obj);								graph->moveable = 0;
-			graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
-			graph->GRect.Ymin += (txtdef1.fSize*10.0);	graph->GRect.Ymax += (txtdef1.fSize*10.0);
+			graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+			graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+			scale.sx.fx = txtdef1.fSize*5.0;			scale.sy.fx = txtdef1.fSize*10.0;
+			graph->Command(CMD_SCALE, &scale, 0L);
 			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
+			cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
 			}
-		mk_table(page, graph->GRect.Xmin, graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0, 1, res_tab);
-		parent->Command(CMD_DROP_GRAPH, page, 0L);
-		for(i = 0; i < nc; i++){
-			if(cols[i]) free(cols[i]);		if(names[i]) free(names[i]);
+		dBounds.Ymin = 0.5;			dBounds.Ymax = ((double)(nr-hr))+0.5;
+		dBounds.Xmin = dmin;		dBounds.Xmax = dmax;
+		for(r = 0, tmp = 1.0; r < (nr-hr); r++, tmp += 1.0) abc[r] = tmp;
+		//plot row results
+		if((graph = new Graph(parent, data, 0L, 0x10)) && (txt_obj = mk_scatt(0x10, r_m, abc, r_ss, nvr+hr, nr-hr, "Mean", "Means <u>+</u> S.D.", "Rows"))){
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+				if(((PlotScatt*)LastOpenGO)->y_tv = new TextValue()){
+					for(i = 0; i < nr; i++) ((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
+					}
+				}
+			free(txt_obj);								graph->moveable = 0;
+			graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+			graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+			scale.sx.fx = cx;							scale.sy.fx = txtdef1.fSize*10.0;
+			graph->Command(CMD_SCALE, &scale, 0L);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
 			}
-		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
-		free(cols);			free(ncols);			free(names);
-		free(res_tab);		free(css);				free(csums);
+		cx = txtdef1.fSize*5.0;
+		//draw anova table and clean up
+		rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+		cy = mk_table(page, cx, cy+txtdef2.fSize, 4, res_tab)+txtdef2.fSize;
+		if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+		free(c_ss);			free(r_ss);
+		free(c_m);			free(r_m);
 		}
-	if(rD) delete rD;		CloseDlgWnd(hDlg);
-	delete Dlg;				free(AnovaDlg);
+	if(vals) {
+		for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+		free(vals);
+		}
+	if(res_tab) {
+		for(i = 0; i < 4; i++) if(res_tab[i]) free(res_tab[i]);
+		free(res_tab);
+		}
+	if (cnames) {
+		for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
+		free(cnames);
+		}
+	if (rnames) {
+		for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
+		free(rnames);
+		}
+	if(nvr) free(nvr);		if(nvc) free(nvc);
+	CloseDlgWnd(hDlg);		delete Dlg;		free(TwAnovDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Friedman's non-parametric two way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void rep_fmanova(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 40, 10, "Input Data"};
+	DlgInfo *FmAnovDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
+		(void*)" column/row headers present"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
+	bool bContinue = false;
+	char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
+	double tmp, cx, cy, dmin, dmax, cchi2, rchi2, prob;
+	double **vals = 0L, **rows = 0L, **cols = 0L, *idx, *cs = 0L, *rs = 0L;
+	double *m, *b1, *b2, *w1, *w2, *trc;
+	RECT rec;
+	scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
+	AccRange *rD =0L, *rDesc;
+	anyResult ares;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(FmAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+	else {
+		data->ValueRec(&rec);
+		rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+		}
+	if(!(Dlg = new DlgRoot(FmAnovDlg, data)))return;
+	hDlg = CreateDlgWnd("Friedman's Non-Parametric Two-Way Anova", 50, 50, 420, 220, 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(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
+				&& (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
+				nc = rec.right-rec.left+1;				nr = rec.bottom-rec.top+1;
+				nvc = (int*)calloc(nc, sizeof(int));	nvr = (int*)calloc(nr, sizeof(int));
+				dmin = HUGE_VAL;						dmax = -HUGE_VAL;
+				if(Dlg->GetCheck(102)) hr = hc = 1;
+				else hr = hc = 0;
+				for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
+				for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
+					if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
+						nvc[c-rec.left]++;				nvr[r-rec.top]++;
+						if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
+						if(ares.value > dmax) dmax = ares.value;
+						if(ares.value < dmin) dmin = ares.value;
+						}
+					}
+				while(!nvc[nc-1] && nc > 1) nc--;
+				while(!nvr[nr-1] && nr > 1) nr--;
+				for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
+				for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
+				for( ; nvr[hr] < mr && hr < nr; hr++);
+				for( ; nvc[hc] < mc && hc < nc; hc++);
+				for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
+				for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
+				for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
+				for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
+				if(res < 0 || mr < 2 || mc < 2) {
+					InfoBox("There are missing data!");
+					for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+					free(vals);			free(nvr);			free(nvc);
+					nvr = nvc = 0L;		vals = 0L;
+					bContinue = true;
+					}
+				delete rD;
+				}
+			break;
+		default:
+			nr = nc = 0;		break;
+			}
+		}while (res < 0);
+	if(res == 1&& (vals) && (cs = (double*)calloc(nr, sizeof(double))) 
+		&& (rs = (double*)calloc(nc, sizeof(double)))
+		&& (cols = (double**)calloc(nc, sizeof(double*)))
+		&& (rows = (double**)calloc(nr, sizeof(double*)))
+		&& (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
+		&& (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
+		&& (idx = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (m = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (b1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (b2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (w1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (w2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+		&& (trc = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))) {
+		//get column and row descriptors
+		for(c = hc; c < nc; c++) {
+			if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
+				cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
+				delete rDesc;
+				}
+			}
+		for(r = hr; r < nr; r++) {
+			if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
+				rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
+				delete rDesc;
+				}
+			}
+		//create ranks
+		for(c = hc; c < nc; c++) if(cols[c-hc] = (double*)calloc(nr, sizeof(double))) {
+			for(r = hr; r < nr; r++) {
+				cols[c-hc][r-hr] = vals[r][c];		idx[r-hr] = (double)(r-hr);
+				}
+			SortArray2(nr-hr, cols[c-hc], idx);		crank(nr-hr, cols[c-hc], &tmp);
+			SortArray2(nr-hr, idx, cols[c-hc]);
+			}
+		for(r = hr; r < nr; r++) if(rows[r-hr] = (double*)calloc(nc, sizeof(double))) {
+			for(c = hc; c < nc; c++) {
+				rows[r-hr][c-hc] = vals[r][c];		idx[c-hc] = (double)(c-hc);
+				}
+			SortArray2(nc-hc, rows[r-hr], idx);		crank(nc-hc, rows[r-hr], &tmp);
+			SortArray2(nc-hc, idx, rows[r-hr]);	
+			}
+		for(r = 0; r < (nr-hr); r++) for(c = 0; c < (nc-hc); c++){
+			cs[r] += cols[c][r];	rs[c] += rows[r][c];
+			}
+		//rank sums and statistics
+		for(r = 0, cchi2 = 0.0; r < (nr-hr); r++) cchi2 += (cs[r]*cs[r]);
+		cchi2 = cchi2 * 12.0 / ((double)((nr-hr)*(nc-hc)*(nr-hr+1))) - 3.0*(nc-hc)*(nr-hr+1);
+		for(c = 0, rchi2 = 0.0; c < (nc-hc); c++) rchi2 += (rs[c]*rs[c]);
+		rchi2 = rchi2 * 12.0 / ((double)((nc-hc)*(nr-hr)*(nc-hc+1))) - 3.0*(nr-hr)*(nc-hc+1);
+		//create report page
+		rep_init();
+		page = new Page(parent, data);
+		mk_header(page, "<b>Friedman's non-parametric two-way ANOVA</b>", data);
+		cx = txtdef1.fSize*5.0;		cy = txtdef1.fSize*10.0;
+		//plot column results
+		for(c = hc; c < nc; c++) {
+			w1[c-hc] = HUGE_VAL;		w2[c-hc] = -HUGE_VAL;
+			for(r = hr; r < nr; r++) {
+				trc[r-hr] = vals[r][c];
+				if(vals[r][c] < w1[c-hc]) w1[c-hc] = vals[r][c];
+				if(vals[r][c] > w2[c-hc]) w2[c-hc] = vals[r][c];
+				}
+			d_quartile(r-hr, trc, b1+c-hc, m+c-hc, b2+c-hc);
+			}
+		dBounds.Xmin = 0.5;			dBounds.Xmax = ((double)(nc-hc))+0.5;
+		dBounds.Ymin = dmin;		dBounds.Ymax = dmax;
+		if((graph = new Graph(parent, data, 0L, 0)) && 
+			(txt_obj = mk_boxplot(0, 0L, m, b1, b2, w1, w2, nvc, nc-hc, "medians", "25-75%", "min/max"))){
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+				if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+					for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
+					}
+				if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Columns");
+				if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
+				}
+			free(txt_obj);								graph->moveable = 0;
+			graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+			graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+			scale.sx.fx = txtdef1.fSize*5.0;			scale.sy.fx = txtdef1.fSize*10.0;
+			graph->Command(CMD_SCALE, &scale, 0L);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
+			}
+		//plot row results
+		for(r = hr; r < nr; r++) {
+			w1[r-hr] = HUGE_VAL;		w2[r-hr] = -HUGE_VAL;
+			for(c = hc; c < nc; c++) {
+				trc[c-hc] = vals[r][c];
+				if(vals[r][c] < w1[r-hr]) w1[r-hr] = vals[r][c];
+				if(vals[r][c] > w2[r-hr]) w2[r-hr] = vals[r][c];
+				if(vals[r][c] < dBounds.Xmin) dBounds.Xmin = vals[r][c];
+				if(vals[r][c] > dBounds.Xmax) dBounds.Xmax = vals[r][c];
+				}
+			d_quartile(c-hc, trc, b1+r-hr, m+r-hr, b2+r-hr);
+			}
+		for(r = hr; r < nr; r++) trc[r-hr] = ((double)(r-hr+1));
+		dBounds.Ymin = 0.5;			dBounds.Ymax = ((double)(nr-hr))+0.5;
+		dBounds.Xmin = dmin;		dBounds.Xmax = dmax;
+		if((graph = new Graph(parent, data, 0L, 0x10)) && 
+			(txt_obj = mk_boxplot(1, m, trc, b1, b2, w1, w2, nvr, nr-hr, "medians", "25-75%", "min/max"))){
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+				if(((BoxPlot*)LastOpenGO)->y_tv = new TextValue()){
+					for(i = 0; i < (nr-hr); i++)((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
+					}
+				if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Rows");
+				if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Location");
+				}
+			free(txt_obj);								graph->moveable = 0;
+			graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+			graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+			scale.sx.fx = cx;							scale.sy.fx = txtdef1.fSize*10.0;
+			graph->Command(CMD_SCALE, &scale, 0L);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		cx = txtdef1.fSize*5.0;			cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+		free(m);	free(b1);	free(b2);	free(w1);	free(w2);	free(trc);
+		rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between columns:</b>");
+		cy += txtdef1.fSize *1.5;
+		prob = chi_dist(fabs(rchi2), nc-hc-1, 0.0);
+#ifdef USE_WIN_SECURE
+		i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
+		if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
+#else
+		i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
+		if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
+#endif
+		else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
+		rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		cy += txtdef1.fSize*2.0;
+		rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between rows:</b>");
+		cy += txtdef1.fSize *1.5;
+		prob = chi_dist(fabs(cchi2), nr-hr-1, 0.0);
+#ifdef USE_WIN_SECURE
+		i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
+		if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
+#else
+		i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
+		if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
+#endif
+		else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
+		rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+		free(rs);		free(cs);		free(idx);
+		}
+	if(cols) {
+		for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
+		free(cols);
+		}
+	if(rows) {
+		for(i = 0; i < nr; i++) if(rows[i]) free(rows[i]);
+		free(rows);
+		}
+	if(vals) {
+		for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+		free(vals);
+		}
+	if (cnames) {
+		for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
+		free(cnames);
+		}
+	if (rnames) {
+		for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
+		free(rnames);
+		}
+	if(nvr) free(nvr);		if(nvc) free(nvc);
+	CloseDlgWnd(hDlg);		delete Dlg;		free(FmAnovDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Two way anova with replica
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TwAnovDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,101,,,LTEXT,2,10,30,60,8\n"
+	"101,102,,,RANGEINPUT,-15,20,40,100,10\n"
+	"102,103,,,LTEXT,3,20,55,53,8\n"
+	"103,,,LASTOBJ,EDVAL1,4,75,55,30,10";
+
+typedef struct _anov_group_info {
+	double *rmeans, *cmeans;
+	int *vpr, *vpc, nvals;
+	double mean;
+	}anov_group_info;
+
+void rep_twoway_anova(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 40, 10, "Input Data"};
+	DlgInfo *TwAnovDlg;
+	double dlpr = 3.0, *cmeans;
+	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables", (void*)"lines per replica:",
+		(void*)&dlpr};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, k, res, ntot, lpr, ngr, r1, r2, c1, c2, iErr;
+	int *vpc, *vpr;
+	double tmp, dn, gMean, SSwithin, SSsubgr, SStotal, SSrows, SScols, SSinteract;
+	double **res_tab = 0L, cx, cy;
+	bool bContinue = false;
+	AccRange *rD =0L;
+	char *mrk;
+	RECT rec;
+	anyResult ares;
+	anov_group_info *agr;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(TwAnovDlg = CompileDialog(TwAnovDlg_Tmpl, dyndata))) return;
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+	else {
+		data->ValueRec(&rec);
+		rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+		}
+	if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
+	hDlg = CreateDlgWnd("Two-Way Anova with Replica", 50, 50, 420, 220, Dlg, 0x0L);
+loop1:
+	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:
+			Dlg->GetValue(103, &dlpr);		lpr = (int)dlpr;
+			break;
+			}
+		}while (res < 0);
+	if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))
+		&& rD->BoundRec(&rec) && (ntot = rD->CountItems())){
+		r1 = rec.top;		r2 = rec.bottom+1;			c1= rec.left;	c2 = rec.right+1;
+		vpc = (int*)calloc(c2-c1+1, sizeof(int));		vpr = (int*)calloc(r2-r1+1, sizeof(int));
+		for(k = iErr = 0; k < 2; k++) {
+			for(i = c1;	i < c2; i++) for(j = r1; j < r2; j++) {
+				data->GetResult(&ares, j, i, false);
+				if(ares.type == ET_VALUE) {
+					vpc[i-c1]++;					vpr[j-r1]++;
+					}
+				}
+			if(!k) {
+				for(i = 0; !vpc[i]; i++);			for(j = 0; !vpr[j]; j++);
+				memset(vpc,0,sizeof(int)*(c2-c1));	memset(vpr,0,sizeof(int)*(r2-r1));
+				c1 += i;		r1 += j;
+				}
+			}
+		while(c2 > c1 && !vpc[c2-c1-1]) c2--;		while(r2 > r1 && !vpr[r2-r1-1]) r2--;
+		ngr = (int)(((double)(r2-r1))/dlpr);
+		if(ngr * lpr < r2 -r1) iErr = 2;
+		agr = (anov_group_info *)calloc(ngr+1, sizeof(anov_group_info));
+		cmeans = (double *)calloc(c2-c1+1, sizeof(double));
+		for(i = 0; i <= ngr; i++) {
+			agr[i].cmeans = (double*)calloc(c2-c1+2, sizeof(double));
+			agr[i].vpc = (int*)calloc(c2-c1+2, sizeof(int));
+			agr[i].rmeans = (double*)calloc(lpr+2, sizeof(double));
+			agr[i].vpr = (int*)calloc(lpr+2, sizeof(int));
+			}
+		for(i = c1; i < c2; i++) for(j = r1; j < r2; j++) {
+			k = (j-r1)/lpr;		data->GetResult(&ares, j, i, false);
+			if(ares.type == ET_VALUE) {
+				agr[k].cmeans[i-c1] += ares.value;		agr[k].vpc[i-c1]++;
+				agr[k].rmeans[j-k*lpr] += ares.value;	agr[k].vpr[j-k*lpr]++;
+				agr[k].mean += ares.value;				agr[k].nvals++;
+				cmeans[i-c1] += ares.value;
+				}
+			else iErr = 1;
+			}
+		for(k = 0; k < ngr; k++) {
+			agr[k].mean /= ((double)(agr[k].nvals));
+			for(i = 0; i < (c2-c1); i++) {
+				agr[k].cmeans[i] /= ((double)(agr[k].vpc[i]));
+				}
+			}
+		for(i = c1, SSwithin = gMean = 0.0, dn = 1.0; i < c2; i++) for(j = r1; j < r2; j++) {
+			k = (j-r1)/lpr;		data->GetResult(&ares, j, i, false);
+			if(ares.type == ET_VALUE) {
+				SSwithin += ((tmp = ares.value-agr[k].cmeans[i-c1])*tmp);
+				gMean += ((ares.value - gMean)/dn);		dn	+=	1.0;
+				}
+			}
+		for(k = 0, SSsubgr = SSrows = 0.0; k < ngr; k++) {
+			for(i = 0; i < (c2-c1); i++) {
+				SSsubgr += (dlpr*((tmp = agr[k].cmeans[i] - gMean) * tmp));
+				}
+			SSrows += ((tmp = (agr[k].mean - gMean)) * tmp);
+			}
+		for(i = c1, SScols = 0.0; i < c2; i++) {
+			cmeans[i-c1] /= ((double)(r2-r1));
+			SScols += ((tmp = cmeans[i-c1]-gMean) * tmp);
+			}
+		SStotal = SSsubgr + SSwithin;		SSrows *= (dlpr *((double)(c2-c1)));
+		SScols *= (dlpr * ((double)ngr));	SSinteract = fabs(SSsubgr - SSrows - SScols);
+		if(!iErr&& (res_tab = (double**)calloc(5, sizeof(double*)))
+			&& (res_tab[0] = (double*)calloc(5, sizeof(double)))
+			&& (res_tab[1] = (double*)calloc(5, sizeof(double)))
+			&& (res_tab[2] = (double*)calloc(5, sizeof(double)))
+			&& (res_tab[3] = (double*)calloc(5, sizeof(double)))
+			&& (res_tab[4] = (double*)calloc(5, sizeof(double)))) {
+			res_tab[0][0] = (double)(ngr-1);				res_tab[1][0] = (double)(c2-c1-1);
+			res_tab[2][0] = res_tab[0][0]* res_tab[1][0];	res_tab[3][0] = (double)(ngr*(c2-c1)*(lpr-1));
+			res_tab[4][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0] + res_tab[3][0];
+			res_tab[0][1] = SSrows;			res_tab[0][2] = res_tab[0][1] / res_tab[0][0];
+			res_tab[1][1] = SScols;			res_tab[1][2] = res_tab[1][1] / res_tab[1][0];
+			res_tab[2][1] = SSinteract;		res_tab[2][2] = res_tab[2][1] / res_tab[2][0];
+			res_tab[3][1] = SSwithin;		res_tab[3][2] = res_tab[3][1] / res_tab[3][0];
+			res_tab[4][1] = SStotal;		res_tab[0][3] = res_tab[0][2] / res_tab[3][2];
+			res_tab[1][3] = res_tab[1][2] / res_tab[3][2];
+			res_tab[2][3] = res_tab[2][2] / res_tab[3][2];
+			res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[3][0]);
+			res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[3][0]);
+			res_tab[2][4] = f_dist(res_tab[2][3], res_tab[2][0], res_tab[3][0]);
+
+
+			rep_init();
+//			dBounds.Xmin = 0.5;				dBounds.Xmax = ((double)nc)+0.5;
+			page = new Page(parent, data);
+			mk_header(page, "<b>Two-Way ANOVA with Replication</b>", data);
+
+			cx = txtdef1.fSize*5.0;		cy = txtdef1.fSize*10.0;
+
+			rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+			cy = mk_table(page, cx, cy+txtdef2.fSize, 3, res_tab)+txtdef2.fSize;
+			if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+			free(res_tab[0]);			free(res_tab[1]);			free(res_tab[2]);
+			free(res_tab[3]);			free(res_tab[4]);			free(res_tab);
+			}
+		for(i = 0; i <= ngr; i++) {
+			free(agr[i].cmeans);					free(agr[i].vpc);
+			free(agr[i].rmeans);					free(agr[i].vpr);
+			}
+		free(vpc);			free(vpr);		free(cmeans);
+		delete rD;
+		switch(iErr) {
+			case 1:		
+				ErrorBox("There are missing Data!");
+				goto loop1;
+			case 2:		
+				ErrorBox("The total number of lines\nmust be a multiple of\nlines per replica.");
+				goto loop1;
+			}
+		}
+		CloseDlgWnd(hDlg);		delete Dlg;		free(TwAnovDlg);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -781,7 +1720,7 @@ void rep_kruskal(GraphObj *parent, DataObj *data)
 		dBounds.Xmin = 0.5;			dBounds.Xmax = (double)maxYR+0.3;
 		if(rV1) delete rV1;			rV1 = 0L;	ranks = ridx = 0L;
 		cy = txtdef1.fSize*10.0;
-		mk_header(page, "<b>Kruskal-Wallis Test for Differences of Location</b>");
+		mk_header(page, "<b>Kruskal-Wallis Test for Differences of Location</b>", data);
 		dBounds.Ymin = HUGE_VAL;	dBounds.Ymax = -HUGE_VAL;
 		// get data into two dimensional array
 		for(nr = maxYR, i = nt = 0; i < nr; i++) {
@@ -842,7 +1781,7 @@ void rep_kruskal(GraphObj *parent, DataObj *data)
 			x[i] = (double)(i+1);		d_quartile(nvals[i], vals[i], by1+i, y+i, by2+i);
 			}
 		// create boxplot
-		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_boxplot(x, y, by1, by2, wy1, wy2,
+		if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, x, y, by1, by2, wy1, wy2,
 			nvals, nr,"Median","25-75%","Min./Max."))){
 			scale.sx.fx = (txtdef1.fSize*5.0);			scale.sy.fx = (txtdef1.fSize*10.0);
 			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
@@ -976,11 +1915,11 @@ void rep_samplestats(GraphObj *parent, DataObj *data)
 		cb = rlp_strcpy(TmpTxt, 100, "<b>Sample Statistics for \"");
 		if(x_info && x_info[0])	cb += rlp_strcpy(TmpTxt+cb, 100-cb, x_info);
 		else cb += rlp_strcpy(TmpTxt+cb, 100-cb, TmpTxt+200);
-		rlp_strcpy(TmpTxt+cb,100-cb, "\"</b>");		mk_header(page, TmpTxt);
+		rlp_strcpy(TmpTxt+cb,100-cb, "\"</b>");		mk_header(page, TmpTxt, data);
 		for(ntot = 0, rD->GetFirst(&nc, &nr); rD->GetNext(&nc, &nr); ) {
 			if(data->GetValue(nr, nc, &val)) src_data[ntot++] = val;
 			}
-		if(ntot > 5 && (graph = new Graph(page, data, 0L))) {
+		if(ntot > 5 && (graph = new Graph(page, data, 0L, 0))) {
 			if(plot = new NormQuant(page, data, src_data, ntot)) {
 				plot->x_info = x_info;		plot->y_info = y_info;
 				}
@@ -1062,19 +2001,19 @@ static double mk_regr_summary(GraphObj *parent, double x, double y, double *dres
 }
 
 static char *RegrDlg_Tmpl =
-	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
-	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
-	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
+	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
 	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,100\n"
 	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
-	"100,101,,,LTEXT,2,10,30,60,8\n"
-	"101,102,,,RANGEINPUT,-15,20,40,100,10\n"
-	"102,103,,,LTEXT,3,10,55,60,8\n"
-	"103,104,,,RANGEINPUT,-16,20,65,100,10\n"
-	"104,105,,,LTEXT,4,10,80,60,8\n"
-	"105,106,,,EDVAL1,5,74,80,25,10\n"
-	"106,107,,,LTEXT,-10,101,80,60,8\n"
-	"107,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
+	"100,+,,,LTEXT,2,10,30,60,8\n"
+	".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+	".,.,,,LTEXT,3,10,55,60,8\n"
+	".,.,,,RANGEINPUT,-16,20,65,100,10\n"
+	".,.,,,LTEXT,4,10,80,60,8\n"
+	".,.,,,EDVAL1,5,74,80,25,10\n"
+	".,.,,,LTEXT,-10,101,80,60,8\n"
+	".,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
 
 void
 rep_regression(GraphObj *parent, DataObj *data)
@@ -1088,12 +2027,15 @@ rep_regression(GraphObj *parent, DataObj *data)
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, n, n1, rx, cx, ry, cy, res, align = 0;
-	bool bContinue = false, bParZ;
+	int x_dtype, y_dtype, nVals, nTxt, nTime;
+	bool bContinue = false, bValid, bParZ;
 	AccRange *rX = 0L, *rY = 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[14], ly[4];
 	char *txt_obj, *x_desc=0L, *y_desc=0L;
+	anyResult xRes, yRes;
+	TextValue *x_tv, *y_tv;
 	Graph *graph;
 	Page *page;
 
@@ -1120,13 +2062,13 @@ rep_regression(GraphObj *parent, DataObj *data)
 			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.");
+				ErrorBox("Range not specified\nor not valid.");
 				bContinue = true;
 				res = -1;
 				}
 			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");
+					ErrorBox("Both ranges must be given\nand must have the same size");
 					bContinue = true;
 					res = -1;
 					}
@@ -1141,12 +2083,51 @@ rep_regression(GraphObj *parent, DataObj *data)
 		&& (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);
+		//analyse data types
+		x_dtype = y_dtype = 0;				x_tv = y_tv = 0L;
+		if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+			}
+		if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+			}
 		rX->GetFirst(&cx, &rx);				rY->GetFirst(&cy, &ry);
 		rep_init();
 		dBounds.Xmin = dBounds.Ymin = HUGE_VAL;		dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
-		for(i = n = 0; i < n1; i++) {
-			if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) 
-				&& data->GetValue(rx, cx, &x[n]) && data->GetValue(ry, cy, &y[n])){
+		//read data into x[] and y[]
+		for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
+			bValid = false;
+			if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
+				bValid = true;
+				if(x_tv) {
+					if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
+					else bValid = false;
+					}
+				else if(x_dtype == ET_DATETIME) {
+					if(xRes.type == ET_DATE || xRes.type == ET_TIME  || xRes.type == ET_DATETIME) dx = xRes.value;
+					else bValid = false;
+					}
+				else {
+					if(xRes.type == ET_VALUE) dx = xRes.value;
+					else bValid = false;
+					}
+				if(y_tv) {
+					if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
+					else bValid = false;
+					}
+				else if(y_dtype == ET_DATETIME) {
+					if(yRes.type == ET_DATE || yRes.type == ET_TIME  || yRes.type == ET_DATETIME) dy = yRes.value;
+					else bValid = false;
+					}
+				else {
+					if(yRes.type == ET_VALUE) dy = yRes.value;
+					else bValid = false;
+					}
+				}
+			if(bValid){
+				x[n] = dx;				y[n] = dy;
 				if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
 				if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
 				if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
@@ -1179,10 +2160,14 @@ rep_regression(GraphObj *parent, DataObj *data)
 		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)){
+		if (n && (graph = new Graph(parent, data, 0L, 0))) {
+			if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
 				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
 				free(txt_obj);
+				if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
+					((Plot*)LastOpenGO)->x_dtype = x_dtype;	((Plot*)LastOpenGO)->y_dtype = y_dtype;
+					((Plot*)LastOpenGO)->x_tv = x_tv;		((Plot*)LastOpenGO)->y_tv = y_tv;
+					}
 				}
 #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", 
@@ -1192,13 +2177,13 @@ rep_regression(GraphObj *parent, DataObj *data)
 			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", 
+			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", 
+			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);
@@ -1210,13 +2195,13 @@ rep_regression(GraphObj *parent, DataObj *data)
 			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\"\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\"\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);
@@ -1244,7 +2229,7 @@ rep_regression(GraphObj *parent, DataObj *data)
 			graph->moveable = 0;
 			graph->GRect.Xmin += (txtdef1.fSize*5.0);		graph->GRect.Xmax += (txtdef1.fSize*5.0);
 			graph->GRect.Ymin += (txtdef1.fSize*10.0);		graph->GRect.Ymax += (txtdef1.fSize*10.0);
-			mk_header(page, "<b>Linear Regression Analysis</b>");
+			mk_header(page, "<b>Linear Regression Analysis</b>", data);
 			res_tab[0][0] = 1;						res_tab[1][0] = df;
 			res_tab[2][0] = df+1.0;					res_tab[0][1] = sxy*sxy/sxx;
 			res_tab[1][1] = syy-res_tab[0][1];		res_tab[2][1] = syy;
@@ -1268,6 +2253,213 @@ rep_regression(GraphObj *parent, DataObj *data)
 	if(x) free(x);				if(y) free(y);
 	if(rX) delete rX;			if(rY) delete rY;		free(RegrDlg);
 }
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Kendall's robust line-fit
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RobLineDlg_Tmpl =
+	"1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
+	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,78\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,+,,,LTEXT,2,10,30,60,8\n"
+	".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+	".,.,,,LTEXT,3,10,55,60,8\n"
+	".,,,LASTOBJ,RANGEINPUT,-16,20,65,100,10";
+
+void
+rep_robustline(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 90, 10, "Nonparametric Regression"};
+	DlgInfo *RegrDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"range for x-data", (void*)"range for y-data"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, k, n, n1, rx, cx, ry, cy, res, align = 0;
+	int x_dtype, y_dtype, nVals, nTxt, nTime;
+	bool bContinue = false, bValid;
+	AccRange *rX = 0L, *rY = 0L;
+	double *x = 0L, *y = 0L, *a = 0L, *b = 0L, c_x, c_y;
+	double dx, dy, slope, intercept;
+	char *txt_obj, *x_desc=0L, *y_desc=0L;
+	scaleINFO scale = {{0.0, 0.45}, {0.0, 0.45}, {0.0, 0.45}};
+	anyResult xRes, yRes;
+	TextValue *x_tv, *y_tv;
+	Plot *plot;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(RegrDlg = CompileDialog(RobLineDlg_Tmpl, dyndata))) return;
+	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+	if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
+	hDlg = CreateDlgWnd("Kendall's robust line-fit", 50, 50, 420, 220, 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(rX) delete rX;					if(rY) delete rY;
+			rX = rY = 0L;
+			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, 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;
+					res = -1;
+					}
+				}
+			}
+		}while (res < 0);
+	for(n1 = n, i = k = 1; i < n; i++) k += i;
+	if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double))) 
+		&& (y = (double*)malloc(n*sizeof(double)))
+		&& (a = (double*)malloc(k*sizeof(double)))
+		&& (b = (double*)malloc(k*sizeof(double)))){
+		x_desc = rX->RangeDesc(data, 0);	y_desc = rY->RangeDesc(data, 0);
+		//analyse data types
+		x_dtype = y_dtype = 0;				x_tv = y_tv = 0L;
+		if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+			}
+		if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+			if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+			else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+			}
+		rX->GetFirst(&cx, &rx);				rY->GetFirst(&cy, &ry);
+		rep_init();
+		dBounds.Xmin = dBounds.Ymin = HUGE_VAL;		dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
+		//read data into x[] and y[]
+		for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
+			bValid = false;
+			if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
+				bValid = true;
+				if(x_tv) {
+					if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
+					else bValid = false;
+					}
+				else if(x_dtype == ET_DATETIME) {
+					if(xRes.type == ET_DATE || xRes.type == ET_TIME  || xRes.type == ET_DATETIME) dx = xRes.value;
+					else bValid = false;
+					}
+				else {
+					if(xRes.type == ET_VALUE) dx = xRes.value;
+					else bValid = false;
+					}
+				if(y_tv) {
+					if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
+					else bValid = false;
+					}
+				else if(y_dtype == ET_DATETIME) {
+					if(yRes.type == ET_DATE || yRes.type == ET_TIME  || yRes.type == ET_DATETIME) dy = yRes.value;
+					else bValid = false;
+					}
+				else {
+					if(yRes.type == ET_VALUE) dy = yRes.value;
+					else bValid = false;
+					}
+				}
+			if(bValid){
+				x[n] = dx;				y[n] = dy;
+				if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
+				if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
+				if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
+				if(dBounds.Ymax < y[n]) dBounds.Ymax = y[n];
+				n++;
+				}
+			}
+		SortArray2(n, x, y);
+		for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
+			if(x[i] != x[j]) {
+				b[k] = (y[j] - y[i])/(x[j] - x[i]);
+				a[k] = y[i] - b[k]*x[i];	k++;
+				}
+			}
+		d_quartile(k, b, 0L, &slope, 0L);		d_quartile(k, a, 0L, &intercept, 0L);
+		slope = slope;		intercept = intercept;
+		if (n && (graph = new Graph(parent, data, 0L, 0))) {
+			if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
+					((Plot*)LastOpenGO)->x_dtype = x_dtype;	((Plot*)LastOpenGO)->y_dtype = y_dtype;
+					((Plot*)LastOpenGO)->x_tv = x_tv;		((Plot*)LastOpenGO)->y_tv = y_tv;
+					}
+				}
+#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", intercept, slope);
+			i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Fitted Line\"\n");
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",intercept,(slope < 0.0 ? '-' : '+'), fabs(slope));
+#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\"\n", intercept, slope);
+			i += sprintf(TmpTxt+i, "Desc=\"Fitted Line\"\n");
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+			sprintf(TmpTxt, "y = %g %c %g * x", intercept, (slope < 0.0 ? '-' : '+'), fabs(slope));
+#endif
+			rep_DrawText(graph, (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);
+			page = new Page(parent, data);					page->Command(CMD_DROP_GRAPH, graph, 0L);
+			graph->moveable = 0;
+			graph->GRect.Xmin += (txtdef1.fSize*5.0);		graph->GRect.Xmax += (txtdef1.fSize*5.0);
+			graph->GRect.Ymin += (txtdef1.fSize*9.0);		graph->GRect.Ymax += (txtdef1.fSize*9.0);
+			mk_header(page, "<b>Kendall's Robust Line-Fit</b>", data);
+			c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+			c_x = graph->GRect.Xmin;
+			j = (int)isqr(k);				i = (int)((double)k/10.0);
+			if(j < 8) j = 8;
+			else if (j >40) j = 40;
+			scale.sx.fx = (graph->GRect.Xmin + graph->GRect.Xmax)/2.0;
+			scale.sy.fx = c_y;
+			graph = new Graph(parent, data, 0L, 0);
+			if(plot = new FreqDist(graph, data, b+(i>>1), k-i, j)){
+				if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all slopes");
+				if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
+				if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+				}
+			graph->Command(CMD_SCALE, &scale, 0L);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			mk_median_report(page, c_x, c_y, b, k, .95, "Slope");
+			scale.sy.fx = c_y = graph->GRect.Ymax + txtdef1.fSize;
+			graph = new Graph(parent, data, 0L, 0);
+			if(plot = new FreqDist(graph, data, a+(i>>1), k-i, j)){
+				if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all intercepts");
+				if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
+				if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+				}
+			graph->Command(CMD_SCALE, &scale, 0L);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			c_y = mk_median_report(page, c_x, c_y, a, k, .95, "Intercept");
+			parent->Command(CMD_DROP_GRAPH, page, 0L);
+			}
+		}
+	CloseDlgWnd(hDlg);
+	delete Dlg;
+	if(x_desc) free(x_desc);	if(y_desc)free(y_desc);
+	if(x) free(x);				if(y) free(y);
+	if(a) free(a);				if(b) free(b);
+	if(rX) delete rX;			if(rY) delete rY;		free(RegrDlg);
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Correlation reports
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1385,16 +2577,16 @@ void rep_correl(GraphObj *parent, DataObj *data, int style)
 		if(rV1) delete rV1;			rV1 = 0L;		use_corr = corr;
 		switch(corr) {
 		case 1:
-			mk_header(page, "<b>Pearsons product moment correlations</b>");
+			mk_header(page, "<b>Pearsons product moment correlations</b>", data);
 			break;
 		case 2:
-			mk_header(page, "<b>Spearmans rank correlations</b>");
+			mk_header(page, "<b>Spearmans rank correlations</b>", data);
 			break;
 		case 3:
-			mk_header(page, "<b>Kendalls non parametric correlations</b>");
+			mk_header(page, "<b>Kendalls non parametric correlations</b>", data);
 			break;
 		default:
-			mk_header(page, "<b>### Correlation Error ###</b>");
+			mk_header(page, "<b>### Correlation Error ###</b>", data);
 			break;
 			}
 		memcpy(&mtext, &txtdef1, sizeof(TextDEF));
@@ -1448,7 +2640,7 @@ void rep_correl(GraphObj *parent, DataObj *data, int style)
 					rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, "---");
 					}
 				else if(style = 1) {		//tiled plots
-					graph = new Graph(parent, data, 0L);
+					graph = new Graph(parent, data, 0L, 0);
 					scale.sx.fx = lmarg+cx*j;			scale.sy.fx = cy;
 					if(plot = new FreqDist(graph, data, rd[i], true)){
 						if(rV1 = new AccRange(rd[i])){
@@ -1496,7 +2688,7 @@ void rep_correl(GraphObj *parent, DataObj *data, int style)
 					r = 0.0;	dn = 0.0;	p = 1.0;			break;
 					}
 				//process result
-				if(style == 0) {			//correlation matrix
+				if(dn > 1.0 && style == 0) {			//correlation matrix
 					if(bHiLite && p < cl && (txt_obj = mk_rect(lmarg+cx*j-cx/2.1, cy-line_inc/4.0, lmarg+cx*j+cx/2.1, 
 						cy+line_inc*3.25, 0x0000ffffL, 0x0080ffffL))) {
 						OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
@@ -1510,11 +2702,14 @@ void rep_correl(GraphObj *parent, DataObj *data, int style)
 					rep_DrawText(page, lmarg+cx*j, cy+line_inc*2.0, false, TXA_HCENTER, &mtext, TmpTxt);
 					if(j == (nr-1)) cy += (line_inc*4.0);
 					}
-				else if(style = 1) {		//tiled plots
-					graph = new Graph(parent, data, 0L);
+				else if(style == 0) {					//corr. matrix but no data
+					if(j == (nr-1)) cy += (line_inc*4.0);
+					}
+				else if(style == 1) {		//tiled plots
+					graph = new Graph(parent, data, 0L, 0);
 					scale.sx.fx = lmarg+cx*j;			scale.sy.fx = cy;
 					info1 = rV1->RangeDesc(data, 2);	info2 = rV2->RangeDesc(data, 2);
-					if(txt_obj = mk_scatt(v1, v2, 0L, 0L, n, "Data", info1, info2)){
+					if(txt_obj = mk_scatt(0, v1, v2, 0L, 0L, n, "Data", info1, info2)){
 						OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
 						free(txt_obj);
 						}
@@ -1538,7 +2733,7 @@ void rep_correl(GraphObj *parent, DataObj *data, int style)
 						graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize, false, TXA_HLEFT, &txtdef1, TmpTxt);
 					if(LastOpenGO)LastOpenGO->SetColor(COL_TEXT, 0x00cb0000L);
 					graph->Command(CMD_SCALE, &scale, 0L);
-					page->Command(CMD_DROP_GRAPH, graph, 0L);
+					if(dn > 1.0) page->Command(CMD_DROP_GRAPH, graph, 0L);
 					if(j == (nr-1)) cy += line_inc;
 					}
 				free(v1);		free(v2);
@@ -1789,8 +2984,8 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 		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,
+		mk_header(page, "<b>Compare Means of Two Groups</b>", data);
+		if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, 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);
@@ -1834,7 +3029,7 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 		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,
+		if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, 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);
diff --git a/rlp_math.cpp b/rlp_math.cpp
index 80b1def..ab5cf56 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -326,6 +326,39 @@ void SortFpArray(int n, lfPOINT *vals)
 		}
 }
 
+//randomize array
+double *randarr(double *v0, int n, long *seed)
+{
+	double r, *v, *v_tmp;
+	int i, j, l;
+
+	if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
+	if(!(v_tmp = (double*)memdup(v0, n *sizeof(double),0))) return 0L;
+	for(l = n, i = 0; i < n; ) {
+		r = ran2(seed);			j = (int)(r *((double)l));
+		if(j < l) {
+			v[i++] = v_tmp[j];
+			if(j < l)memcpy(v_tmp+j, v_tmp+j+1, (l-j)*sizeof(double));
+			l--;
+			}
+		}
+	return v;
+}
+
+//resample array
+double *resample(double *v0, int n, long *seed)
+{
+	double r, *v;
+	int i, j;
+
+	if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
+	for(i = 0; i < n; ) {
+		r = ran2(seed);			j = (int)(r *((double)n));
+		if(j < n) v[i++] = v0[j];
+		}
+	return v;
+}
+
 //---------------------------------------------------------------------------
 // Cubic Spline Interpolation
 // Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
@@ -635,6 +668,7 @@ double lognorm_freq(double x, double m, double s)
 //chi square distribution
 double chi_dist(double x, double df, double)
 {
+	if(x <= 0.0) return 1.0;
 	return gammq(df/2.0, x/2.0);
 }
 
@@ -672,7 +706,7 @@ double pois_dist(double x, double m, double)
 //f-distribution
 double f_dist(double f, double df1, double df2)
 {
-	return betai(df2/2.0, df1/2.0, df2/(df2+df1*f));
+	return f > 0.0 ? betai(df2/2.0, df1/2.0, df2/(df2+df1*f)): 1.0;
 }
 
 double f_freq(double x, double df1, double df2)
@@ -685,6 +719,96 @@ double f_freq(double x, double df1, double df2)
 	return exp(a-b+c+d);
 }
 
+//---------------------------------------------------------------------------
+// The Weibull distribution
+//---------------------------------------------------------------------------
+double weib_dist(double x, double shape, double scale)
+{
+	double dn=1.0, sum, term, tmp;
+
+	if(shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
+	if(x <= 0.0) return 0.0;
+	term = -pow(x/scale, shape);		tmp = fabs(term);
+	if(tmp < 2.22e-16) return tmp;
+	if (tmp > 0.697) return -exp(term)+1.0;
+	x = sum = term;
+	do {				//do taylor series
+		dn += 1.0 ;		term *= x/dn;		sum += term;
+		}while (fabs(term) > fabs(sum) * 2.22e-16) ;
+	return -sum;
+}
+
+double weib_freq(double x, double shape, double scale)
+{
+	double tmp1, tmp2;
+
+	if (shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
+	if (x < 0) return 0.0;
+	if(x > -HUGE_VAL && x < HUGE_VAL) {
+		if(x == 0.0 && shape < 1.0) return HUGE_VAL;
+		tmp1 = pow(x / scale, shape - 1.0);
+		tmp2 = tmp1 * (x / scale);
+		return shape * tmp1 * exp(-tmp2) / scale;
+		}
+	return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+// The Cauchy (Lorentz) distribution
+//---------------------------------------------------------------------------
+double cauch_dist(double x, double loc, double scale)
+{
+	double y;
+
+	if(scale < 0.0) return HUGE_VAL;
+	x = (x - loc) / scale;
+	if(x > -HUGE_VAL && x < HUGE_VAL) {
+		if (fabs(x) > 1.0) {
+			y = atan(1.0/x)/_PI;		return (x > 0) ? 1.0-y : -y;
+			} 
+		else return 0.5 + atan(x)/_PI;
+		}
+	return HUGE_VAL;
+}
+
+double cauch_freq(double x, double loc, double scale)
+{
+	double y;
+
+	if(scale < 0.0) return HUGE_VAL;
+	if(x > -HUGE_VAL && x < HUGE_VAL) {
+		y = (x - loc) / scale;
+		return 1.0 / (_PI * scale * (1.0 + y*y));
+		}
+	return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+// The Logistic distribution
+//---------------------------------------------------------------------------
+double logis_dist(double x, double loc, double scale)
+{
+	if(scale < 0.0) return HUGE_VAL;
+	x = exp(-(x - loc) / scale);
+	if(x > -HUGE_VAL && x < HUGE_VAL) {
+		return 1.0/(1.0 + x);
+		}
+	return HUGE_VAL;
+}
+
+double logis_freq(double x, double loc, double scale)
+{
+	double e, f;
+
+	x = fabs((x - loc) / scale);
+	if(x > -HUGE_VAL && x < HUGE_VAL) {
+		e = exp(-x);     f = 1.0 + e;	
+		return  e / (scale * f*f);
+		}
+	return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
 // Shapiro-Wilk W test and its significance level
 // Algorithm AS 394, 1995, Appl. Statist. 44(4), 547-551
 //
@@ -899,7 +1023,10 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 	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);
 	else if(sf == lognorm_dist) *df = lognorm_freq(x, df1, df2);
-	else {
+	else if(sf == weib_dist) *df = weib_freq(x, df1, df2);
+	else if(sf == cauch_dist) *df = cauch_freq(x, df1, df2);
+	else if(sf == logis_dist) *df = logis_freq(x, df1, df2);
+	else {		//numerical differentiation
 		y1 = (sf)(x * 0.995, df1, df2);		y2 = (sf)(x * 1.005, df1, df2);
 		*df = (y2-y1)*100.0/x;
 		}
@@ -1246,7 +1373,7 @@ double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double
 
 
 //linear regression
-double d_regression(double *x, double *y, int n, char *dest, DataObj *data)
+double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
 {
 	double sx, sy, dx, dy, sxy, sxx, syy, sdy, df;
 	double res[10];		// slope, intercept, mean x, mean y, SE of slope, 
@@ -1281,6 +1408,7 @@ double d_regression(double *x, double *y, int n, char *dest, DataObj *data)
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if (ra)	memcpy(ra, res, 10 * sizeof(double));
 	return n;
 }
 
@@ -1303,7 +1431,7 @@ 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 *results)
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
 {
 	double *da, *ta, u1, u2, su, su1, ts, dn1 = n1, dn2 = n2;
 	double res[9];
@@ -1343,9 +1471,7 @@ double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data,
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
-	else if(results) {
-		for(i = 0; i < 9; i++) results[i] = res[i];
-		}
+	if (ra)	memcpy(ra, res, 9 * sizeof(double));
 	return res[8];
 }
 
@@ -1383,7 +1509,7 @@ 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) {
+	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)));
@@ -1393,7 +1519,7 @@ double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data,
 }
 
 //t-test for paired samples
-double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data)
+double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
 {
 	double sx, sy, mx, my, df, cov, sd, t, p;
 	int i, r, c;
@@ -1406,9 +1532,9 @@ double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data)
 	sd = sqrt((sx+sy-2*cov)/n);
 	t = (mx-my)/sd;					df = (n-1);
 	p = betai(0.5*df, 0.5, df/(df+t*t));
+	res[0] = mx;	res[1] = sqrt(sx);	res[5] = p;
+	res[2] = my;	res[3] = sqrt(sy);	res[4] = n;
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		res[0] = mx;	res[1] = sqrt(sx);	res[5] = p;
-		res[2] = my;	res[3] = sqrt(sy);	res[4] = n;
 		rD->GetFirst(&c, &r);
 		for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
 			data->SetValue(r, c, res[i]);
@@ -1416,11 +1542,12 @@ double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data)
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if (ra)	memcpy(ra, res, 6 * sizeof(double));
 	return p;
 }
 
 //f-test
-double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
+double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
 {
 	int i, r, c;
 	double sx, sy, mx, my, d, df1, df2, p;
@@ -1439,9 +1566,9 @@ double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 		}
 	p = 2.0 * betai(df2/2.0, df1/2.0, df2/(df2+df1*d));
 	if(p > 1.0) p = 2.0-p;
+	res[0] = mx;	res[1] = sqrt(sx);	res[2] = n1;
+	res[3] = my;	res[4] = sqrt(sy);	res[5] = n2;
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		res[0] = mx;	res[1] = sqrt(sx);	res[2] = n1;
-		res[3] = my;	res[4] = sqrt(sy);	res[5] = n2;
 		rD->GetFirst(&c, &r);
 		for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
 			data->SetValue(r, c, res[i]);
@@ -1449,14 +1576,121 @@ double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if (ra)	memcpy(ra, res, 6 * sizeof(double));
 	return p;
 }
 //---------------------------------------------------------------------------
+// Simple one way anova
+//---------------------------------------------------------------------------
+bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss)
+{
+	int i, j, ntot;
+	double tmp, *csums, *css, ssa, ssw, sst, mtot, d;
+
+	if(!(csums = (double*)calloc(n+1, sizeof(double)))
+		|| !(css = (double*)calloc(n+1, sizeof(double)))) return false;
+
+	for(i = ntot = 0, mtot = 0.0, d = 1.0; i< n; i++){
+		for(j = 0, csums[i] = 0.0, tmp = 1.0; j < nv[i]; j++, d+=1.0, tmp +=1.0) {
+			mtot += (vals[i][j] - mtot)/d;		
+			csums[i] += (vals[i][j] -csums[i])/tmp;
+			}
+		ntot += nv[i];
+		}
+	for(i = 0; i < n; i++) {
+		for(j = 0, css[i] = 0.0; j < nv[i]; j++) {
+			tmp = vals[i][j] - csums[i];	css[i] += (tmp*tmp);
+			}
+		}
+	for(i = 0, ssa = ssw = sst = 0.0;  i < n; i++) {
+		tmp =(csums[i] - mtot);		ssa += (tmp*tmp) * ((double)nv[i]);
+		ssw += css[i];
+		}
+	sst = ssa + ssw;
+	res_tab[0][0] = n - 1;				res_tab[1][0] = ntot - n;
+	res_tab[2][0] = ntot -1;			res_tab[0][1] = ssa;
+	res_tab[1][1] = ssw;				res_tab[2][1] = sst;
+	res_tab[0][2] = ssa/res_tab[0][0];	res_tab[1][2] = ssw/res_tab[1][0];
+	res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
+	res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
+	if(gm) *gm = mtot;
+	if(means) *means = csums;			else free(csums);
+	if(ss) *ss = css;					else free(css);
+	return true;
+}
+
+//---------------------------------------------------------------------------
+// Bartlett's Test for homogeneity of variances
+// RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 398 ff.
+//---------------------------------------------------------------------------
+bool bartlett(int n, int *nc, double *ss, double *chi2)
+{
+	int i, sdf, df;
+	double mss, mlss, *lnss, cf;
+
+	if(!n || !nc || !ss || !chi2) return false;
+	if(!(lnss = (double*)malloc(n * sizeof(double))))return false;
+	for(i = sdf = 0, mss = mlss = cf = 0.0; i < n; i++) {
+		sdf += (df = nc[i]-1);				lnss[i] = log(ss[i]);
+		mss += (ss[i] * ((double)df));		mlss += (lnss[i] * ((double)df)); 
+		cf += (1.0/((double)df));
+		}
+	*chi2 = ((double)sdf) * log(mss/((double)sdf)) - mlss;
+	cf -= (1.0/((double)sdf));				cf = 1.0 + cf/(3.0 * ((double)(n-1)));
+	*chi2 /= cf;
+	// P = chi_dist(*chi2, n-1, 0);
+	free(lnss);		return true;
+}
+//---------------------------------------------------------------------------
+// Leven's Test for homogeneity of variances
+//---------------------------------------------------------------------------
+bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P)
+{
+	int i, j;
+	bool bRet = false;
+	double cm, **res_tab, **cols;
+	
+	if(!n || !nv || !means || !vals) return false;
+	//setup matrix for results
+	if((res_tab = (double**)calloc(3, sizeof(double*)))
+		&& (res_tab[0] = (double*) malloc(5*sizeof(double)))
+		&& (res_tab[1] = (double*) malloc(5*sizeof(double)))
+		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))
+		&& (cols = (double**)calloc(n+1, sizeof(double*)))) bRet = true;
+	//allocate mem for data
+	for(i = 0; bRet && i<n; i++) {
+		if(!(cols[i]=(double*)malloc((nv[i]+1)*sizeof(double)))) bRet = false;
+		}
+	//data are absolute differences to mean ...
+	for(i = 0, cm = 0.0; bRet && i < n; i++) {
+		switch(type) {
+			case 1:			//use means
+				cm = means[i];								break;
+			case 2:			//use medians
+				d_quartile(nv[i], vals[i], 0L, &cm, 0L);	break;
+			}
+		for(j = 0; j < nv[i]; j++) {
+			cols[i][j] = vals[i][j] > cm ? vals[i][j] - cm : cm - vals[i][j];
+			}
+		}
+	//Levene's test statistic is based on ANOVA of the differences
+	if(bRet && (bRet = do_anova1(n, nv, cols, res_tab, 0L, 0L, 0L))){
+		if(F) *F = res_tab[0][3];				if(P) *P = res_tab[0][4];
+		}
+	//clean up
+	if(bRet) {
+		for(i = 0; i < n; i++) if(cols[i]) free(cols[i]);
+		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+		free(cols);								free(res_tab);	
+		}
+	return bRet;
+}
+
+//---------------------------------------------------------------------------
 // Modules from the R-project
 //
 //---------------------------------------------------------------------------
 #define M_1_SQRT_2PI	0.398942280401432677939946059934	/* 1/sqrt(2pi) */
-#define M_LN2 log(2.0)
 /*
  *  Copyright (C) 1998       Ross Ihaka
  *  Copyright (C) 2000--2005 The R Development Core Team
@@ -1661,7 +1895,7 @@ double ptukey(double q, double rr, double cc, double df, int lower_tail, int log
 
     if (df > dlarg)	return wprob(q, rr, cc);
     f2 = df * 0.5;								// calculate leading constant
-    f2lf = ((f2 * log(df)) - (df * M_LN2)) - gammln(f2);
+    f2lf = ((f2 * log(df)) - (df * log(2.0))) - gammln(f2);
     f21 = f2 - 1.0;
     // integral is divided into unit, half-unit, quarter-unit, or eighth-unit length intervals 
 	//    depending on the value of the degrees of freedom.
@@ -1842,16 +2076,11 @@ static char *dt_day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
 
 static char *dt_days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
 
-typedef struct rlp_datetime {
-	int aday, year, doy, month, dom, dow, hours, minutes;
-	double seconds;
-}rlp_datetime;
-
 static bool leapyear(int year) {
 	return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
 }
 
-static int year2aday(int y)
+int year2aday(int y)
 {
 	int aday, y1;
 
@@ -1868,6 +2097,47 @@ static void set_dow(rlp_datetime *dt)
 	dt->dow = (dt->aday %7)+1;
 }
 
+void add_date(rlp_datetime *base, rlp_datetime *inc)
+{
+	int i, dom;
+
+	if(base) {
+		if(base->month < 1) base->month = 1;
+		if(inc) {
+			base->seconds += inc->seconds;
+			if(base->seconds >= 60.0) {
+				base->minutes++;		base->seconds -= 60.0;
+				}
+			base->minutes += inc->minutes;
+			if(base->minutes >= 60) {
+				base->hours++;			base->minutes -= 60;
+				}
+			base->hours += inc->hours;
+			if(base->hours >= 24) {
+				base->dom++;			base->hours -= 24;
+				}
+			base->year += inc->year;	base->dom += inc->dom;
+			base->month += inc->month;
+			}
+		dom = dt_monthl[base->month-1];
+		if(leapyear(base->year) && base->month == 2) dom = 29;
+		if(base->dom > dom) {
+			base->month++;			base->dom -= dom;
+			}
+		if(base->month > 12) {
+			base->year++;			base->month -= 12;
+			}
+		base->aday = year2aday(base->year);
+		for(i = base->doy = 0; i < (base->month-1); i++) {
+			dom = dt_monthl[i];
+			if(i == 1 && leapyear(base->year)) dom = 29;
+			base->doy += dom;
+			}
+		base->doy += base->dom;
+		base->aday += base->doy;	set_dow(base);
+		}
+}
+
 static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 {
 	int i, j, k;
@@ -1982,7 +2252,7 @@ static int parse_date (rlp_datetime *dt, char *src, char *fmt)
 	return j;
 }
 
-static char *date2text(rlp_datetime *dt, char *fmt)
+char *date2text(rlp_datetime *dt, char *fmt)
 {
 	static char res[80];
 	int i, pos;
@@ -2142,7 +2412,7 @@ static char *date2text(rlp_datetime *dt, char *fmt)
 	return res;
 }
 
-static double date2value(rlp_datetime *dt)
+double date2value(rlp_datetime *dt)
 {
 	double res;
 
@@ -2154,7 +2424,7 @@ static double date2value(rlp_datetime *dt)
 	return res;
 }
 
-static void parse_datevalue(rlp_datetime *dt, double dv)
+void parse_datevalue(rlp_datetime *dt, double dv)
 {
 	int i, j, d;
 
diff --git a/rlplot.cpp b/rlplot.cpp
index aa95e1e..22cfa15 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -1,4 +1,4 @@
-//RLPlot.cpp, Copyright 2000-2006 R.Lackner
+//rlplot.cpp, Copyright 2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -32,6 +32,8 @@ Graph *CurrGraph = 0L;
 Axis **CurrAxes = 0L;
 dragHandle *CurrHandle = 0L;
 UndoObj Undo;
+fmtText DrawFmtText;
+
 int cGraphs = 0;
 int cPlots = 0;
 int cPages = 0;
@@ -151,8 +153,7 @@ double
 Symbol::GetSize(int select)
 {
 	switch(select) {
-	case SIZE_MINE:
-	case SIZE_SYMBOL:
+	case SIZE_MINE:		case SIZE_SYMBOL:
 		return size;
 	case SIZE_SYM_LINE:
 		return SymLine.width;
@@ -169,8 +170,7 @@ bool
 Symbol::SetSize(int select, double value)
 {
 	switch(select & 0xfff){
-	case SIZE_MINE:
-	case SIZE_SYMBOL:
+	case SIZE_MINE:		case SIZE_SYMBOL:
 		size = value;
 		return true;
 	case SIZE_SYM_LINE:
@@ -218,15 +218,18 @@ Symbol::SetColor(int select, DWORD col)
 void
 Symbol::DoPlot(anyOutput *target)
 {
-	int ix, iy, rx, ry, atype;
+	int ix, iy, rx, ry, crx, cry, atype;
+	double sc;
+	long ncpts;
 	lfPOINT fip;
-	POINT pts[5];
+	POINT pts[14], *cpts;
 	FillDEF cf;
 
 	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;
+		atype == SYM_TRIADF || atype == SYM_DIAMONDF || atype == SYM_4STARF ||
+		atype == SYM_5GONF || atype == SYM_5STARF || atype == SYM_6STARF) cf.color = SymLine.color;
 	if(type & SYM_POS_PARENT) {
 		if(!parent) return;
 		fip.fx = parent->GetSize(SIZE_XCENTER);
@@ -239,26 +242,62 @@ Symbol::DoPlot(anyOutput *target)
 	default:
 	case SYM_CIRCLE:		//circle
 	case SYM_CIRCLEF:		//filled circle
+	case SYM_CIRCLEC:		//circle with center point
+	case SYM_1QUAD:		case SYM_2QUAD:		case SYM_3QUAD:
 		rx = target->un2ix(size/2.0);		ry = target->un2iy(size/2.0);
 		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+		if(atype == SYM_CIRCLEC) {
+			crx = target->un2ix(size/5.0);	cry = target->un2iy(size/5.0);
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+			}
+		else if(atype == SYM_1QUAD || atype == SYM_2QUAD || atype == SYM_3QUAD) {
+			ncpts = 0L;			cf.color = SymLine.color;		target->SetFill(&cf);
+			if(atype == SYM_1QUAD) {
+				if(!(cpts = MakeArc(ix, iy, rx, 0x04, &ncpts)) || !ncpts) return;
+				cpts[0].x = ix + rx;		cpts[0].y = iy;
+				}
+			else if(atype == SYM_2QUAD) {
+				if(!(cpts = MakeArc(ix, iy, rx, 0x06, &ncpts)) || !ncpts) return;
+				cpts[0].x = ix;				cpts[0].y = iy+rx;
+				}
+			else if(atype == SYM_3QUAD) {
+				if(!(cpts = MakeArc(ix, iy, rx, 0x07, &ncpts)) || !ncpts) return;
+				cpts[0].x = ix-rx;			cpts[0].y = iy;
+				}
+			cpts[ncpts-1].x = ix;			cpts[ncpts-1].y = iy-rx;
+			cpts[ncpts].x = ix;				cpts[ncpts].y = iy;				ncpts++;
+			cpts[ncpts].x = cpts[0].x;		cpts[ncpts].y = cpts[0].y;		ncpts++;
+			target->oPolygon(cpts, ncpts);	free(cpts);
+			}
 		rx--;ry--;			//smaller marking rectangle
 		break;
 	case SYM_RECT:			//rectange (square)
 	case SYM_RECTF:			//filled rectangle
+	case SYM_RECTC:			//square with center point
 		rx = target->un2ix(size/2.25676);	ry = target->un2iy(size/2.25676);
 		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+		if(atype == SYM_RECTC) {
+			crx = target->un2ix(size/6.0);	cry = target->un2iy(size/6.0);
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+			}
 		break;
 	case SYM_TRIAU:			//triangles up and down, open or closed
-	case SYM_TRIAUF:	case SYM_TRIAD:		case SYM_TRIADF:
+	case SYM_TRIAUF:	case SYM_TRIAD:		case SYM_TRIADF:		case SYM_TRIADC:
+	case SYM_TRIAUC:	case SYM_TRIAUL:	case SYM_TRIAUR:		case SYM_TRIADL:
+	case SYM_TRIADR:
 		rx = target->un2ix(size/1.48503);	ry = target->un2iy(size/1.48503);
 		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		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
+		//patch by anonymous
+		if(atype == SYM_TRIAU || atype == SYM_TRIAUF || atype == SYM_TRIAUL 
+			|| atype == SYM_TRIAUR || atype == SYM_TRIAUC) {
 			pts[0].y = pts[2].y = pts[3].y = iy+target->un2iy(size*0.38878f);
 			pts[1].y = iy-target->un2iy(size*0.77756f);
 			}
@@ -267,10 +306,23 @@ Symbol::DoPlot(anyOutput *target)
 			pts[1].y = iy+target->un2iy(size*0.77756f);
 			}
 		target->oPolygon(pts, 4);
+		if(atype == SYM_TRIAUC || atype == SYM_TRIADC) {
+			crx = target->un2ix(size/6.0);	cry = target->un2iy(size/6.0);
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+			}
+		else if(atype == SYM_TRIAUL || atype == SYM_TRIADL) {
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			pts[2].x = pts[1].x;			target->oPolygon(pts, 4);
+			}
+		else if(atype == SYM_TRIAUR || atype == SYM_TRIADR) {
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			pts[0].x = pts[3].x = pts[1].x;	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);
+	case SYM_DIAMOND:	case SYM_DIAMONDF:		case SYM_DIAMONDC:
+		rx = target->un2ix(size/1.59588);	ry = target->un2iy(size/1.59588);
 		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		pts[0].x = pts[2].x = pts[4].x = ix;		
@@ -278,8 +330,78 @@ Symbol::DoPlot(anyOutput *target)
 		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);
+		if(atype == SYM_DIAMONDC) {
+			crx = target->un2ix(size/6.0);	cry = target->un2iy(size/6.0);
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+			}
 		rx--;									ry--;
 		break;
+	case SYM_4STAR:		case SYM_4STARF:
+		rx = target->un2ix(size/1.4);	ry = target->un2iy(size/1.4);
+		crx = target->un2ix(size/6.0);	cry = target->un2iy(size/6.0);
+		pts[0].x = pts[8].x = ix-rx;	pts[0].y = pts[4].y = pts[8].y = iy;
+		pts[1].x = pts[7].x = ix-crx;	pts[1].y = pts[3].y = iy - cry;
+		pts[2].x = pts[6].x = ix;		pts[2].y = iy - ry;
+		pts[3].x = pts[5].x = ix+crx;	pts[4].x = ix + rx;
+		pts[5].y = pts[7].y = iy+cry;	pts[6].y = iy + ry;
+		target->SetFill(&cf);			target->oPolygon(pts, 9);
+		break;
+	case SYM_5GON:		case SYM_5GONF:		case SYM_5GONC:
+		sc = 1.4;
+		rx = target->un2ix(size/sc);	ry = target->un2iy(size/sc);
+		crx = target->un2ix(size/sc * 0.951057);	
+		cry = target->un2iy(size/sc * 0.309017);
+		pts[0].x = ix-crx;		pts[0].y = pts[2].y = iy-cry;	pts[1].x = ix;
+		pts[1].y = iy-ry;		pts[2].x = ix+crx;
+		crx = target->un2ix(size/sc * 0.587785);	
+		cry = target->un2iy(size/sc * 0.809017);
+		pts[3].x = ix + crx;	pts[4].x = ix - crx;
+		pts[3].y = pts[4].y = iy+cry;
+		pts[5].x = pts[0].x;	pts[5].y = pts[0].y;
+		target->SetFill(&cf);			target->oPolygon(pts, 6);
+		if(atype == SYM_5GONC) {
+			crx = target->un2ix(size/6.0);	cry = target->un2iy(size/6.0);
+			cf.color = SymLine.color;		target->SetFill(&cf);
+			target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+			}
+		break;
+	case SYM_5STAR:		case SYM_5STARF:
+		sc = 1.4;
+		rx = target->un2ix(size/sc);	ry = target->un2iy(size/sc);
+		crx = target->un2ix(size/sc * 0.951057);	
+		cry = target->un2iy(size/sc * 0.309017);
+		pts[0].x = ix-crx;		pts[0].y = pts[1].y = pts[3].y = pts[4].y = iy-cry;
+		pts[2].x = pts[7].x = ix;		pts[2].y = iy-ry;		pts[4].x = ix+crx;
+		crx = target->un2ix(size/sc * 0.23);
+		pts[1].x = ix - crx;	pts[3].x = ix + crx;
+		crx =  target->un2ix(size/sc * 0.36);
+		cry = target->un2iy(size/sc * 0.11);
+		pts[5].x = ix + crx;	pts[5].y = pts[9].y = iy +	cry;	pts[9].x = ix - crx;
+		pts[7].y = iy + target->un2iy(size/sc * 0.38);
+		crx = target->un2ix(size/sc * 0.587785);	
+		cry = target->un2iy(size/sc * 0.809017);
+		pts[6].x = ix + crx;	pts[8].x = ix - crx;
+		pts[6].y = pts[8].y = iy+cry;
+		pts[10].x = pts[0].x;	pts[10].y = pts[0].y;
+		target->SetFill(&cf);			target->oPolygon(pts, 11);
+		break;
+	case SYM_6STAR:		case SYM_6STARF:
+		sc = 1.4 / 0.86;				rx = target->un2ix(size/sc);
+		sc = 1.4 / 0.5;					ry = target->un2iy(size/sc);
+		pts[0].x = pts[10].x = pts[12].x = ix - rx;
+		pts[4].x = pts[6].x = ix + rx;	pts[2].x = pts[8].x = ix;
+		pts[0].y = pts[1].y = pts[3].y = pts[4].y = pts[12].y = iy - ry;
+		pts[6].y = pts[7].y = pts[9].y = pts[10].y = iy + ry;	
+		sc = 1.4 / 0.29;				rx = target->un2ix(size/sc);
+		pts[1].x = pts[9].x = ix - rx;	pts[3].x = pts[7].x = ix + rx;
+		sc = 1.4 / 0.52;				rx = target->un2ix(size/sc);
+		pts[5].x = ix +rx;	pts[11].x = ix - rx;	pts[5].y = pts[11].y = iy;
+		sc = 1.4;
+		rx = target->un2ix(size/sc);	ry = target->un2iy(size/sc);
+		pts[2].y = iy - ry;				pts[8].y = iy + ry;
+		target->SetFill(&cf);			target->oPolygon(pts, 13);
+		break;
 	case SYM_STAR:			//star is a combination of + and x symbols
 	case SYM_PLUS:			//draw a + sign
 	case SYM_HLINE:		case SYM_VLINE:
@@ -297,10 +419,10 @@ Symbol::DoPlot(anyOutput *target)
 	case SYM_CROSS:			//draw a x symbol
 		rx = target->un2ix(size/2.5);		ry = target->un2iy(size/2.5);
 		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
-		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);
+		pts[0].x = ix - rx - 2;				pts[1].x = ix + rx + 3;
+		pts[0].y = iy - ry - 2;				pts[1].y = iy + ry + 3;
+		target->oPolyline(pts, 2);			Swap(pts[0].y, pts[1].y);
+		pts[1].y -= 1;						pts[0].y -= 1;
 		target->oPolyline(pts, 2);
 		break;
 	case SYM_TEXT:
@@ -308,14 +430,14 @@ Symbol::DoPlot(anyOutput *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);
+		DrawFmtText.SetText(target, SymTxt->text, &ix, &iy);
 		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;
+	rDims.left = ix-rx-1;				rDims.right = ix+rx+2;
+	rDims.top = iy-ry-1;				rDims.bottom = iy+ry+2;
 }
 
 bool 
@@ -853,6 +975,7 @@ Bar::DoMark(anyOutput *o, bool mark)
 	int i;
 
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		i = 2*o->un2ix(BarLine.width);		//increase size of rectangle for marks
 		IncrementMinMaxRect(&mrc, i);
@@ -1162,6 +1285,7 @@ DataLine::DoMark(anyOutput *o, bool mark)
 {
 	if(pts && cp && o){
 		if(mark){
+			if(mo) DelBitmapClass(mo);				mo = 0L;
 			memcpy(&mrc, &rDims, sizeof(RECT));
 			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
 			mo = GetRectBitmap(&mrc, o);
@@ -1450,6 +1574,7 @@ DataPolygon::DoMark(anyOutput *o, bool mark)
 {
 	if(pts && cp && o){
 		if(mark){
+			if(mo) DelBitmapClass(mo);				mo = 0L;
 			memcpy(&mrc, &rDims, sizeof(RECT));
 			IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
 			mo = GetRectBitmap(&mrc, o);
@@ -1577,32 +1702,34 @@ RegLine::DoPlot(anyOutput *o)
 	for (cp = i = 0; i <= 200; i++){
 		dValid = true;
 		switch(type & 0x700) {
-		case 0x100:					//logarithmic x
+		case 0x100:						//logarithmic x
 			if(dValid = x > defs.min4log) x1 = log10(x);
 			break;
-		case 0x200:					//reciprocal x
+		case 0x200:						//reciprocal x
 			if(dValid = fabs(x) > defs.min4log) x1 = 1.0/x;
 			break;
-		case 0x300:					//square root x
+		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);
+		if(dValid) {
+			y = a + b*x1;
+			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(y >= cliprc.Ymin && y <= cliprc.Ymax) {
+				pn.x = o->fx2ix(x);	pn.y = o->fy2iy(y);
+				AddToPolygon(&cp, pts, &pn);
+				}
 			}
 		x += d;
 		}
@@ -1732,7 +1859,7 @@ void
 SDellipse::DoPlot(anyOutput *o)
 {
 	int i;
-	double a1, b1, a2, b2, fv, k1, k2, ss1, ss2, np, x, dx, si, csi;
+	double a1, b1, a2, b2, fv, k1, k2, ss1, ss2, np, x, dx, si, csi, fac, fac2;
 	lfPOINT fp, fip;
 	POINT p1, *tmppts;
 
@@ -1759,11 +1886,16 @@ SDellipse::DoPlot(anyOutput *o)
 	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++) {
+	switch(type & 0x60000) {
+		case 0x20000:		fac = 2.0;		break;
+		case 0x40000:		fac = 3.0;		break;
+		default:			fac = 1.0;		break;
+		}
+	fac2 = fac*fac;			dx = sd2/100.0*fac;
+	for(i = 0, cp = 0, x = -(sd2*fac); i < 2; i++) {
 		do {
-			fv = (x*x)/ss2;
-			fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1) : 0.0;
+			fv = (x*x)/(ss2*fac2);
+			fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1*fac2) : 0.0;
 			fv = i ? fv : -fv;
 			fp.fx = mx + x * csi - fv * si;
 			fp.fy = my + x * si + fv * csi;
@@ -1795,8 +1927,8 @@ SDellipse::DoPlot(anyOutput *o)
 				}
 			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;
+			}while((x += dx) < (sd2*fac) && x > (-sd2*fac));
+		x = sd2*fac;
 		dx *= -1.0;
 		}
 	o->SetLine(&LineDef);
@@ -1912,10 +2044,8 @@ ErrorBar::ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, in
 {
 	FileIO(INIT_VARS);
 	fPos.fx = x;		fPos.fy = y;
-	ferr = err;
-	type = which;
-	Id = GO_ERRBAR;
-	data = d;
+	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;
@@ -2053,6 +2183,7 @@ ErrorBar::DoMark(anyOutput *o, bool mark)
 	LineDEF OldLine;
 
 	if(mark){
+		if(mo) DelBitmapClass(mo);			mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
 		i = 3*o->un2ix(ErrLine.width);		//increase size of rectangle for marks
@@ -2062,7 +2193,7 @@ ErrorBar::DoMark(anyOutput *o, bool mark)
 		DoPlot(o);							o->UpdateRect(&mrc, false);
 		memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
 		}
-	else RestoreRectBitmap(&mo, &mrc, o);
+	else if(mo) RestoreRectBitmap(&mo, &mrc, o);
 }
 
 bool
@@ -2292,9 +2423,8 @@ Arrow::DoPlot(anyOutput *o)
 		}
 	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);
+	IncrementMinMaxRect(&rDims, 3*o->un2ix(LineDef.width)+3);
+	Redraw(o);
 }
 
 void
@@ -2310,26 +2440,23 @@ Arrow::DoMark(anyOutput *o, bool mark)
 		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);
+		if(mo) DelBitmapClass(mo);					mo = 0L;
+		if(dh1 && dh2) {
+			memcpy(&mrc, &rDims, sizeof(RECT));		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+			mo = GetRectBitmap(&mrc, o);			Redraw(o);
+			dh1->DoPlot(o);		dh2->DoPlot(o);
+			}
+		else {
+			memcpy(&mrc, &rDims, sizeof(RECT));		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+			mo = GetRectBitmap(&mrc, o);			LineDef.color = 0x00000000L;
+			LineDef.width = OldLine.width *3.0;		Redraw(o);
+			LineDef.width = OldLine.width;			LineDef.color = OldLine.color ^ 0x00ffffffL;
+			Redraw(o);								o->UpdateRect(&mrc, false);
+			memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+			}
 		}
-	memcpy(&LineDef, &OldLine, sizeof(LineDEF));
-	o->UpdateRect(&rDims, false);
+	else if(mo) RestoreRectBitmap(&mo, &mrc, o);
 }
 
 bool
@@ -2356,6 +2483,7 @@ Arrow::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_FLUSH:
 		if (dh1) DeleteGO(dh1);			dh1 = 0L;
 		if (dh2) DeleteGO(dh2);			dh2 = 0L;
+		if(mo) DelBitmapClass(mo);		mo = 0L;
 		if(ssRef) free(ssRef);			ssRef = 0L;
 		if(name) free(name);			name = 0L;
 		return true;
@@ -2802,6 +2930,7 @@ Whisker::DoMark(anyOutput *o, bool mark)
 	LineDEF OldLine;
 
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
 		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
@@ -4194,6 +4323,7 @@ Brick::DoMark(anyOutput *o, bool mark)
 	int i;
 
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
 		mo = GetRectBitmap(&mrc, o);
@@ -4626,6 +4756,7 @@ DropLine3D::DoMark(anyOutput *o, bool mark)
 	int i;
 
 	if(mark) {
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
 		mo = GetRectBitmap(&mrc, o);
@@ -5030,6 +5161,7 @@ void
 Line3D::DoMark(anyOutput *o, bool mark)
 {
 	if(mark) {
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
 		mo = GetRectBitmap(&mrc, o);
@@ -5197,7 +5329,6 @@ Label::~Label()
 {
 	HideTextCursor();
 	Command(CMD_FLUSH, 0L, 0L);
-	if(fmt_txt) delete(fmt_txt);			fmt_txt = 0L;
 	if(bModified)Undo.InvalidGO(this);
 }
 
@@ -5255,6 +5386,9 @@ Label::SetColor(int select, DWORD col)
 void
 Label::DoPlot(anyOutput *o)
 {
+	if(this != CurrGO && m1 >=0 && m2 >=0) {
+		m1 = m2 = -1;
+		}
 	if(is3D && parent && parent->Command(CMD_SET_GO3D, this, o)) return;
 	DoPlotText(o);
 }
@@ -5297,8 +5431,12 @@ Label::DoMark(anyOutput *o, bool mark)
 		if(parent && parent->parent) o->ShowLine(pts, 5, TextDef.ColTxt);
 		ShowCursor(o);	CurrGO = this;		CurrLabel = this;
 		}
+	else if(m1 >= 0 && m2 >= 0) {
+		m1 = m2 = -1;
+		parent->Command(CMD_REDRAW, 0L, o);
+		}
 	else {
-		HideTextCursor();
+		HideTextCursor();				m1 = m2 = -1;
 		bgLine.color = bgcolor;			o->SetLine(&bgLine);
 		//in dialogs parent has no parent
 		if(parent && parent->parent) o->oPolyline(pts, 5);
@@ -5315,7 +5453,7 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 {
 	MouseEvent *mev;
 	scaleINFO *scale;
-	int cb;
+	int i, cb;
 
 	if(cmd != CMD_SET_DATAOBJ && !parent) return false;
 	switch (cmd) {
@@ -5326,6 +5464,11 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 		fDist.fx *= scale->sx.fy;				fDist.fy *= scale->sy.fy;
 		TextDef.fSize *= scale->sx.fy;			TextDef.iSize = 0;
 		return true;
+	case CMD_HIDEMARK:
+		if(m1 >=0 && m2 >=0 && m1 != m2) {
+			m1 = m2 = -1;						return true;
+			}
+		return false;
 	case CMD_FLUSH:
 		if(CurrLabel == this) CurrLabel = 0L;
 		if(TextDef.text) free(TextDef.text);	TextDef.text = 0L;
@@ -5340,17 +5483,70 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
-	case CMD_CURRLEFT:
-		if(o && CursorPos >0 && TextDef.text && fmt_txt) {
+	case CMD_SHIFTLEFT:		case CMD_CURRLEFT:
+		if(o && CursorPos >0 && TextDef.text) {
 			Undo.ValInt(this, &CursorPos, 0L);
-			bModified = true;		fmt_txt->cur_left(&CursorPos);			ShowCursor(o);
+			DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+			bModified = true;
+			if(cmd == CMD_SHIFTLEFT) {
+				if(CursorPos && CursorPos == m1) {
+					DrawFmtText.cur_left(&CursorPos);
+					m1 = CursorPos;		ShowCursor(o);
+					}
+				else if(CursorPos && CursorPos == m2) {
+					DrawFmtText.cur_left(&CursorPos);
+					m2 = CursorPos;		ShowCursor(o);
+					if(parent) parent->Command(CMD_REDRAW, 0L, o); 
+					}
+				else if(CursorPos){
+					m2 = CursorPos;
+					DrawFmtText.cur_left(&CursorPos);
+					m1 = CursorPos;		ShowCursor(o);
+					}
+				}
+			else {
+				if(m1 >= 0 && m2 >= 0 && parent) {
+					m1 = m2 = -1;						parent->Command(CMD_REDRAW, 0L, o);
+					}
+				DrawFmtText.cur_left(&CursorPos);		ShowCursor(o);
+				}
+			if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
 			return true;
 			}
 		return false;
-	case CMD_CURRIGHT:
-		if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text) && fmt_txt) {
+	case CMD_SHIFTRIGHT:	case CMD_CURRIGHT:
+		if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text)) {
 			Undo.ValInt(this, &CursorPos, 0L);
-			bModified = true;		fmt_txt->cur_right(&CursorPos);			ShowCursor(o);
+			DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+			bModified = true;
+			if(cmd == CMD_SHIFTRIGHT) {
+				if(CursorPos == m1 && TextDef.text[m1]) {
+					DrawFmtText.cur_right(&CursorPos);
+					m2 = CursorPos;		ShowCursor(o);
+					memcpy(&rm2, &Cursor, sizeof(RECT));
+					if(parent) parent->Command(CMD_REDRAW, 0L, o); 
+					}
+				else if(CursorPos == m2 && TextDef.text[m2]) {
+					DrawFmtText.cur_right(&CursorPos);
+					m2 = CursorPos;		ShowCursor(o);
+					memcpy(&rm2, &Cursor, sizeof(RECT));
+					}
+				else if(TextDef.text[CursorPos]){
+					if(m1 < 0) {
+						m1 = CursorPos;		ShowCursor(o);
+						}
+					DrawFmtText.cur_right(&CursorPos);
+					m2 = CursorPos;		ShowCursor(o);
+					}
+				else return false;
+				}
+			else {
+				if(m1 >= 0 && m2 >= 0 && parent) {
+					m1 = m2 = -1;						parent->Command(CMD_REDRAW, 0L, o);
+					}
+				DrawFmtText.cur_right(&CursorPos);		ShowCursor(o);
+				}
+			if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
 			return true;
 			}
 		return false;
@@ -5361,22 +5557,35 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_BACKSP:
 		SetModified();
 		if(CursorPos <=0 && o) {
-			if(parent->Id == GO_MLABEL) {
+			if(parent && 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
+		DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+		DrawFmtText.cur_left(&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);
+			Undo.String(this, &TextDef.text, 0L);
+			if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+			if(CheckMark() && m2 < (cb = (int) strlen(TextDef.text))) {
+				Undo.ValInt(this, &m1, UNDO_CONTINUE);
+				Undo.ValInt(this, &m2, UNDO_CONTINUE);
+				rlp_strcpy(TextDef.text + m1, cb, TextDef.text + m2);
+				CursorPos = m1;			m1 = m2 = -1;
+				}
+			else {
+				DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+				cb = CursorPos;		DrawFmtText.cur_right(&cb);
+				cb -= CursorPos;	if(cb < 1) cb = 1;
+				rlp_strcpy(TextDef.text + CursorPos, TMP_TXT_SIZE, TextDef.text + CursorPos + cb);
+				}
+			if(o) {
+				RedrawEdit(o);			ShowCursor(o);
+				}
 			}
 		else if(TextDef.text && parent->Id == GO_MLABEL) {
 			parent->Command(CMD_SETFOCUS, this, o);
@@ -5430,16 +5639,50 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_MOUSE_EVENT:
 		mev = (MouseEvent *) tmpl;
 		switch (mev->Action) {
+		case MOUSE_MOVE:
+			if((mev->StateFlags & 0x01) && ObjThere(mev->x, mev->y)) {
+				i = CursorPos;				CalcCursorPos(mev->x, mev->y, o);
+				if(CurrLabel && CurrLabel != this) {
+					CurrLabel->Command(CMD_HIDEMARK, tmpl, o);
+					}
+				CurrGO = CurrLabel = this;
+				if(i == CursorPos) return true;
+				if(CursorPos > m1 && CursorPos < m2) {
+					if(m1 < 0) m1 = CursorPos;
+					else if(m2 != CursorPos)m2 = CursorPos;
+					parent->Command(CMD_REDRAW, 0L, o);
+					}
+				else {
+					if(m1 < 0) m1 = CursorPos;
+					else if(m2 != CursorPos)m2 = CursorPos;
+					if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
+					}
+				return true;
+				}
+			break;
 		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);
+				CalcCursorPos(mev->x, mev->y, o);		
+				if(o->MrkRect && (void*)o->MrkRect == (void*)this) o->MrkMode = MRK_NONE;
+				if(m1 < 0) m1 = CursorPos;			ShowCursor(o);
 				o->ShowMark(this, MRK_GODRAW);
-				return true;
+				}
+			else if(m1 >= 0 && m2 >= 0) {
+				m1 = m2 = -1;		DoPlot(o);
 				}
 			break;
 			}
 		break;
+	case CMD_TEXTTHERE:
+		if(ObjThere(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) {
+			CalcCursorPos(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y, o);
+			CalcRect(o);
+			m1 = m2 = CursorPos;						CurrGO = this;								
+			return true;
+			}
+		m1 = m2 = -1;
+		return false;
 	case CMD_AUTOSCALE:
 		if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
 			&& (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
@@ -5463,7 +5706,6 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 			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){
@@ -5492,6 +5734,7 @@ Label::Track(POINT *p, anyOutput *o)
 	int i;
 
 	if(!parent) return;
+	m1 = m2 = -1;
 	if(parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM){
 		parent->Track(p, o);
 		return;
@@ -5519,9 +5762,9 @@ Label::CalcRect(anyOutput *o)
 	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;
+	DrawFmtText.SetText(0L, TextDef.text, &ix, &iy);
+	if(TextDef.text && TextDef.text[0]) {
+		if(!(DrawFmtText.oGetTextExtent(o, &rx, &ry, 0))) return false;
 		rx++;
 		}
 	else {
@@ -5542,7 +5785,7 @@ Label::CalcRect(anyOutput *o)
 	else if(TextDef.Align & TXA_VBOTTOM) {
 		rc.Ymin -= ry;				rc.Ymax -= ry;
 		}
-	if(fmt_txt && fmt_txt->oGetTextExtent(o, &rx1, &ry, CursorPos)){
+	if(DrawFmtText.oGetTextExtent(o, &rx1, &ry, CursorPos)){
 		rx = CursorPos ? (int)rx1 : 0;
 		}
 	else rx = 0;
@@ -5601,7 +5844,38 @@ Label::SetModified()
 void
 Label::DoPlotText(anyOutput *o)
 {
+	static LineDEF yLine = {0.0, 1.0, 0x0000ffff, 0x0};
+	static FillDEF yFill = {0, 0x0000ffff, 1.0, 0L, 0x0000ffff};
+	POINT mpts[5];
+	int i;
+
 	if(!parent || !o) return;
+	if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this) {
+		i = CursorPos;							CursorPos = m1;
+		CalcRect(o);							memcpy(&rm1, &Cursor, sizeof(RECT));
+		CursorPos = m2;							CalcRect(o);
+		memcpy(&rm2, &Cursor, sizeof(RECT));	CursorPos = i;
+		if(CurrGO == this) ShowCursor(o);
+		else CalcRect(o);
+		if(m2 > m1) {
+			mpts[0].x = mpts[4].x = rm1.left;	mpts[1].x = rm1.right;
+			mpts[0].y = mpts[4].y = rm1.top;	mpts[1].y = rm1.bottom;
+			mpts[2].x = rm2.right;				mpts[2].y = rm2.bottom;
+			mpts[3].x = rm2.left;				mpts[3].y = rm2.top;
+			}
+		else {
+			mpts[0].x = mpts[4].x = rm2.left;	mpts[1].x = rm2.right;
+			mpts[0].y = mpts[4].y = rm2.top;	mpts[1].y = rm2.bottom;
+			mpts[2].x = rm1.right;				mpts[2].y = rm1.bottom;
+			mpts[3].x = rm1.left;				mpts[3].y = rm1.top;
+			}
+		o->SetLine(&yLine);						o->SetFill(&yFill);
+		o->oPolygon(mpts, 5, 0L);
+		}
+	else {
+		m1 = m2 = -1;
+		if(CurrGO == this) ShowCursor(o);
+		}
 	defDisp = o;
 	if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
 	switch(flags & 0x03) {
@@ -5626,13 +5900,29 @@ Label::DoPlotText(anyOutput *o)
 	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);
+		DrawFmtText.SetText(o, TextDef.text, &ix, &iy);
 		}
 	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);
+	if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this && fabs(TextDef.RotBL) < 0.01) {
+		o->CopyBitmap(mpts[0].x, mpts[0].y, o, mpts[0].x, mpts[0].y,
+			mpts[2].x - mpts[0].x, mpts[2].y - mpts[0].y, true);
+		}
+	if(m1 >= 0 && m2 >= 0) o->UpdateRect(&rDims, false);
+}
+
+bool
+Label::CheckMark()
+{
+	int m;
+
+	if(m1 < 0 || m2 < 0 || m1 == m2) return false;
+	if(m1 < m2) return true;
+	//come here on right to left mark: swap m1 and m2
+	m = m1;		m1 = m2;	m2 = m;
+	return	true;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -5821,17 +6111,10 @@ mLabel::Command(int cmd, void *tmpl, anyOutput *o)
 	scaleINFO *scale;
 
 	switch (cmd) {
-	case CMD_MOUSE_EVENT:
+	case CMD_MOUSE_EVENT:		case CMD_TEXTTHERE:
 		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;
@@ -6198,8 +6481,8 @@ TextFrame::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
-	case CMD_ADDCHAR:
-		if(tmpl && o) AddChar(o, *((unsigned char*)tmpl));
+	case CMD_ADDCHARW:	case CMD_ADDCHAR:
+		if(tmpl && o) AddChar(o, *((int *)tmpl));
 		return true;
 	case CMD_DELETE:
 		if(o) DelChar(o);
@@ -6302,6 +6585,9 @@ TextFrame::Command(int cmd, void *tmpl, anyOutput *o)
 		cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
 		ShowCursor(o);
 		return true;
+	case CMD_TEXTTHERE:
+		if(IsInRect(&rDims, ((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) return true;
+		return false;
 	case CMD_MOUSE_EVENT:
 		mev = (MouseEvent *) tmpl;
 		switch (mev->Action) {
@@ -6491,10 +6777,11 @@ TextFrame::lines2text()
 }
 
 void
-TextFrame::AddChar(anyOutput *o, unsigned char c)
+TextFrame::AddChar(anyOutput *o, int c)
 {
 	int i, j, h, w, maxw;
 	bool brd;
+	char *txt1;
 
 	if(cur_pos.y >= nlines) return;
 	if(!lines || !lines[cur_pos.y]) return;
@@ -6513,7 +6800,22 @@ TextFrame::AddChar(anyOutput *o, unsigned char c)
 	i = j = (int)strlen((char*)lines[cur_pos.y])+1;
 	has_m1 = has_m2 = false;
 	if(c >= 32 || c == '\n') {
-		while(j) {
+		if(c > 254 && (txt1 = (char*)malloc(10))) {
+#ifdef USE_WIN_SECURE
+			w = sprintf_s(txt1, 10, "&#%d;", c);
+#else
+			w = sprintf(txt1, "&#%d;", c);
+#endif
+			for(j = j+w; j>0; j--) {
+				lines[cur_pos.y][j] = lines[cur_pos.y][j-w];
+				if((j-w) == cur_pos.x){
+					for(i = 0; i < w; i++) lines[cur_pos.y][j-w+i] = txt1[i];
+					j = 0;					cur_pos.x += w;
+					}
+				}
+			free(txt1);
+			}
+		else 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;
@@ -6544,14 +6846,17 @@ TextFrame::AddChar(anyOutput *o, unsigned char c)
 void
 TextFrame::DelChar(anyOutput *o)
 {
-	int i;
+	int i, cb, x;
+
 	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;
+		lines2text();			Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+		cb = x = cur_pos.x;			fmt_txt.cur_right(&x);
+		cb = x - cb;	if(cb < 1) cb = 1;
+		for(i = cur_pos.x; lines[cur_pos.y][i]; i++) {
+			if(!(lines[cur_pos.y][i] = lines[cur_pos.y][i+cb])) 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; 
@@ -7327,7 +7632,7 @@ Bezier::Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, dou
 	if(!parent) return;
 	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
 	if(type == 0 && (Values = (lfPOINT*)malloc(4 * cpts * sizeof(lfPOINT)))) {
-		merr = 0.01 * Units[defs.cUnits].convert * res;
+		merr = 0.01 * res / Units[defs.cUnits].convert;
 		FitCurve(fpts, cpts, merr);
 		Values[nPoints].fx = fpts[cpts-1].fx;	Values[nPoints].fy = fpts[cpts-1].fy;
 		for(i = 0; i < nPoints; i++) {
@@ -8188,19 +8493,15 @@ LegItem::Command(int cmd, void *tmpl, anyOutput *o)
 	GraphObj **tmpPlots;
 
 	switch(cmd){
+	case CMD_TEXTTHERE:
+		if(Desc && Desc->Command(cmd, tmpl, o)) return true;
+		return false;
 	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;
@@ -8399,6 +8700,10 @@ Legend::Command(int cmd, void *tmpl, anyOutput *o)
 	int i;
 
 	switch(cmd){
+	case CMD_TEXTTHERE:
+		if(Items) for(i = 0; i< nItems; i++) 
+			if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
+		return false;
 	case CMD_MOUSE_EVENT:
 		if(o && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) {
 			if(Items) for(i = 0; i< nItems; i++) 
@@ -8426,18 +8731,6 @@ Legend::Command(int cmd, void *tmpl, anyOutput *o)
 		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++) {
@@ -8560,10 +8853,11 @@ Legend::HasErr(LineDEF *ld, int err, char *desc)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Graphs are graphic objects containing plots, axes, and drawn objects
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Graph::Graph(GraphObj *par, DataObj *d, anyOutput *o):GraphObj(par, d)
+Graph::Graph(GraphObj *par, DataObj *d, anyOutput *o, int style):GraphObj(par, d)
 {
 	Graph::FileIO(INIT_VARS);
 	Disp = o;		Id = GO_GRAPH;		cGraphs++;	bModified = true;
+	if(style & 0x10) y_axis.flags |= AXIS_INVERT;
 	if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
 }
 
@@ -8857,40 +9151,11 @@ Graph::Command(int cmd, void *tmpl, anyOutput *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(Disp)CurrDisp = Disp;
+		if(Disp)CurrDisp = Disp;		bDialogOpen = false;
 		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);
@@ -9112,7 +9377,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
 		if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
-		else if(CurrGO && tmpl && *((int*)tmpl) == 13) {
+		else if(CurrGO && CurrGO->Id != GO_LABEL && tmpl && *((int*)tmpl) == 13) {
 			CurrGO->PropertyDlg();
 			}
 	case CMD_CURRUP:	case CMD_CURRDOWN:
@@ -9126,6 +9391,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		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(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
 			}
 		else {
 			if(type == GT_3D && Plots) {
@@ -9136,6 +9402,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 					}
 				}
 			else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+			else if(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
 			}
 		return false;
 	case CMD_MOVE_TOP:	case CMD_MOVE_UP:
@@ -9291,7 +9558,9 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		if(!tmpl) return false;
 		Undo.SetDisp(o ? o : CurrDisp);
 		PasteObj = (GraphObj*)tmpl;
-		if(PasteObj->Id == GO_GRAPH) {
+		if(PasteObj->Id == GO_GRAPH || PasteObj->Id == GO_POLYLINE || PasteObj->Id == GO_POLYGON 
+			|| PasteObj->Id == GO_RECTANGLE || PasteObj->Id == GO_ROUNDREC || PasteObj->Id == GO_ELLIPSE
+			|| PasteObj->Id == GO_BEZIER) {
 			ToolMode = TM_PASTE;			o->MouseCursor(MC_PASTE, false);
 			return true;
 			}
@@ -9300,51 +9569,55 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_MOUSE_EVENT:
 		mev = (MouseEvent *)tmpl;		defs.SetDisp(o);
 		if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
+			ToolMode == TM_STANDARD && (mev->StateFlags & 24) == 0 &&
 			(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;					SuspendAnimation(o, true);
-			if((ToolMode & 0xff) == TM_STANDARD || (ToolMode & 0xff) == TM_ZOOMIN){
-				rc_mrk.left = mev->x;		rc_mrk.top = mev->y;
+			if(CurrGO && (CurrGO->Id == GO_TEXTFRAME || CurrGO->Id == GO_LABEL) && CurrGO->Command(cmd, tmpl, o)) return true;
+			CurrGO = 0L;		rc_mrk.left = mev->x;		rc_mrk.top = mev->y;
+			if((ToolMode == TM_TEXT || ToolMode == TM_STANDARD) && Command(CMD_TEXTTHERE, tmpl, o)) {
+				o->CheckMenu(TM_TEXT, false);		o->CheckMenu(TM_STANDARD, true);
+				ToolMode = TM_STANDARD;				return true;
 				}
+			SuspendAnimation(o, true);
 			}
 		if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
 		switch(mev->Action) {
 		case MOUSE_RBUP:
-			Undo.SetDisp(o);
-			i = ToolMode;
-			ToolMode = TM_STANDARD;
+			i = ToolMode;							ToolMode = TM_STANDARD;
 			mev->Action = MOUSE_LBUP;				//fake select
-			Command(cmd, tmpl, o);					ToolMode = i;
+			CurrGO = 0L;		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:
+			Undo.SetDisp(o);							bDialogOpen = true;
 			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);
+				if(CurrGO->Command(CMD_CONFIG, 0L, o))	return Command(CMD_REDRAW, 0L, o);
 				}
 			else if(CurrGO->Id < GO_PLOT) {
 				if(CurrGO->PropertyDlg()) {
-					bModified = true;
-					return Command(CMD_REDRAW, 0L, o);
+					bModified = true;					return Command(CMD_REDRAW, 0L, o);
 					}
 				}
 			else if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
 			else o->HideMark();
-			TrackGO = 0L;	CurrLabel = 0L;
+			TrackGO = 0L;	CurrLabel = 0L;			bDialogOpen = false;
 			if(CurrGO == this) CurrGO = 0L;
 			return false;
 		case MOUSE_LBUP:
+			if(bDialogOpen) {
+				bDialogOpen = false;					return false;
+				}
 			Undo.SetDisp(o);		SuspendAnimation(o, false);
 			if(Id == GO_GRAPH && parent && parent->Id == GO_SPREADDATA){
 				CurrGO = TrackGO = 0L;
-				CurrGraph = this;
+				CurrGraph = 0L;
 				}
 		case MOUSE_MOVE:
 			if(mev->Action == MOUSE_MOVE && !(mev->StateFlags & 0x01)) return false;
@@ -9352,18 +9625,28 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			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)){
-					if(Id == GO_GRAPH)CurrGraph = this;		return true;
+			if(Plots && NumPlots > 0) for(i = NumPlots-1; i>=0; i--){
+				if(Plots[i] && Plots[i]->Command(cmd, tmpl, o)){
+					if(Plots[i]->Id != GO_GRAPH && Id == GO_GRAPH) CurrGraph = this;
+					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 &&
+			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_TEXTTHERE:
+		//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;
+		break;
 	case CMD_SETSCROLL:
 		if(o) {
 			if(!(o->ActualSize(&rc)))return false;
@@ -9567,7 +9850,7 @@ Graph::CreateAxes(int templ)
 			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 |
+		if((Axes[1] = new Axis(this, data, &y_axis, y_axis.flags | 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); 
@@ -9784,8 +10067,10 @@ Graph::CreateAxes(int templ)
 		break;
 		}
 	if(Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH && NumAxes > 1) {
-		if(((Plot*)Plots[0])->x_tv) if(Axes[0])Axes[0]->atv = ((Plot*)Plots[0])->x_tv->Copy();
-		if(((Plot*)Plots[0])->y_tv) if(Axes[1])Axes[1]->atv = ((Plot*)Plots[0])->y_tv->Copy();
+		if(((Plot*)Plots[0])->x_tv && Axes[0])Axes[0]->atv = ((Plot*)Plots[0])->x_tv->Copy();
+		else if(((Plot*)Plots[0])->x_dtype == ET_DATETIME)x_axis.flags |= AXIS_DATETIME;
+		if(((Plot*)Plots[0])->y_tv && Axes[1])Axes[1]->atv = ((Plot*)Plots[0])->y_tv->Copy();
+		else if(((Plot*)Plots[0])->y_dtype == ET_DATETIME)y_axis.flags |= AXIS_DATETIME;
 		}
 }
 
@@ -9816,7 +10101,7 @@ Graph::DoScale(scaleINFO* sc, anyOutput *o)
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Pages are graphic objects containing graphs and drawn objects
-Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L)
+Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L, 0)
 {
 	FileIO(INIT_VARS);
 	cGraphs--;		cPages++;		Id = GO_PAGE;	bModified = true;
@@ -9889,12 +10174,14 @@ Page::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_MOUSE_EVENT:
 		return Graph::Command(cmd, tmpl, o);
 	case CMD_REDRAW:
-		Disp->StartPage();		DoPlot(Disp);		Disp->EndPage();
+		if(Disp) {
+			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() && 
+		if((g = new Graph(this, data, Disp, 0)) && g->PropertyDlg() && 
 			Command(CMD_DROP_GRAPH, g, o))return true;
 		else if(g) DeleteGO(g);
 		return false;
diff --git a/rlplot.h b/rlplot.h
index 70d1971..db6fa4a 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -29,7 +29,6 @@ inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
 #define _SQRT2	1.4142135623730950488016887242096980785696718753769
 
 #ifdef _WINDOWS					//platform is windows
-#pragma warning( disable : 4997 )
 #include <windows.h>
 #if _MSC_VER >= 1400
 #define USE_WIN_SECURE
@@ -44,7 +43,6 @@ inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
 #define w_char wchar_t
 #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; 
@@ -117,14 +115,17 @@ enum {CMD_NONE, CMD_ADDCHAR, CMD_ADDCHARW, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELE
 	CMD_SET_LINE, CMD_SAVE_SYMBOLS, CMD_SAVE_TICKS, CMD_SAVE_BARS, CMD_SAVE_BARS_CONT,
 	CMD_SAVE_ERRS, CMD_SAVE_ARROWS, CMD_SAVE_DROPLINES, CMD_SAVE_LABELS, CMD_UNLOCK, CMD_SYMTEXT_UNDO,
 	CMD_FILLRANGE, CMD_BUSY, CMD_ERROR, CMD_CLEAR_ERROR, CMD_SETPARAM, CMD_SETFUNC,
-	CMD_HIDE_MARK, CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
+	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, CMD_COL_MOUSE,
-	CMD_MARKOBJ, CMD_SCALE};
+	CMD_MARKOBJ, CMD_SCALE, CMD_GETFILENAME, CMD_TEXTTHERE, CMD_HIDEMARK};
 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};
+	SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_CIRCLEC, SYM_RECTC, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR,
+	SYM_TRIADC, SYM_TRIADL, SYM_TRIADR, SYM_DIAMONDC, SYM_4STAR, SYM_4STARF, SYM_5GON, SYM_5GONF, 
+	SYM_5GONC, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD, SYM_3QUAD,
+	SYM_TEXT = 0x004f, 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, 
@@ -237,6 +238,11 @@ typedef struct {
 	double scale;				//zoom factor
 	}ZoomDEF;
 
+typedef struct rlp_datetime {
+	int aday, year, doy, month, dom, dow, hours, minutes;
+	double seconds;
+}rlp_datetime;
+
 // 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
@@ -259,6 +265,7 @@ typedef struct {
 #define AXIS_LOG          0x1000
 #define AXIS_RECI         0x2000
 #define AXIS_SQR          0x3000
+#define AXIS_DATETIME     0x4000		// its a date- or time axis
 #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
@@ -539,6 +546,11 @@ typedef struct _fmt_txt_info {
 	char *txt;
 }fmt_txt_info;
 
+typedef struct _fmt_uc_info {
+	int tag, cb;
+	w_char *uc_txt;
+}fmt_uc_info;
+
 public:
 	fmtText();
 	fmtText(anyOutput *o, int x, int y, char *txt);
@@ -559,13 +571,15 @@ private:
 	bool SetTextDef(TextDEF *td, int idx);
 	bool Parse();
 	void DrawBullet(anyOutput *o, int x, int y, int type, double size, DWORD lc, DWORD fc);
+	bool DrawFormattedW(anyOutput *o);
 	void DrawFormatted(anyOutput *o);
 
 	char *src;
 	POINT pos;
-	int n_split;
+	int n_split, n_split_W, uc_state;
 	DWORD flags;
 	fmt_txt_info *split_text;
+	fmt_uc_info *split_text_W;
 };
 
 class TextValue {
@@ -1054,6 +1068,8 @@ public:
 	void Track(POINT *p, anyOutput *o);
 
 private:
+	anyOutput *mo;
+	RECT mrc;
 	dragHandle *dh1, *dh2;
 	POINT pts[5];
 	lfPOINT pos1, pos2;
@@ -1399,6 +1415,7 @@ public:
 	void CalcCursorPos(int x, int y, anyOutput *o);
 	void SetModified();
 	void DoPlotText(anyOutput *o);
+	bool CheckMark();
 	TextDEF *GetTextDef(){return &TextDef;};
 
 private:
@@ -1407,15 +1424,14 @@ private:
 	DWORD flags, bgcolor;
 	TextDEF TextDef;
 	LineDEF bgLine;
-	int ix, iy, CursorPos;
+	int ix, iy, m1, m2, CursorPos;
 	bool is3D;
-	RECT Cursor;
+	RECT Cursor, rm1, rm2;
 	POINT pts[5];
 	POINT *ssRef;
 	long cssRef;
 	anyOutput *defDisp;
 	bool bModified, bBGvalid;
-	fmtText *fmt_txt;
 };
 
 class mLabel:public GraphObj{
@@ -1478,7 +1494,7 @@ private:
 	void text2lines(anyOutput *o);
 	void lines2text();
 	void ShowCursor(anyOutput *o);
-	void AddChar(anyOutput *o, unsigned char c);
+	void AddChar(anyOutput *o, int c);
 	void DelChar(anyOutput *o);
 	void CalcCursorPos(int x, int y, anyOutput *o);
 	void ReplMark(anyOutput *o, char *ntext);
@@ -1676,6 +1692,7 @@ public:
 	int use_xaxis, use_yaxis, use_zaxis;		//this plot uses its own axes
 	lfPOINT xBounds, yBounds, zBounds;	//like Bounds but in 3D space
 	int hidden;						//plot (layer) is not visible
+	int x_dtype, y_dtype, z_dtype;	//data types
 	char *x_info, *y_info, *z_info;	//descriptor used e.g. for axis label or legend
 	char *data_desc;				//descriptor for data, used for legend etc
 	TextValue *x_tv, *y_tv;			//TextValue object for ordinal axes
@@ -1710,7 +1727,7 @@ public:
 	Label **Labels;
 
 	PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
-	PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars);
+	PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars, ErrorBar **errs);
 	PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin);
 	PlotScatt(int src);
 	~PlotScatt();
@@ -1761,6 +1778,7 @@ class FreqDist:public Plot {
 public:
 	FreqDist(GraphObj *par, DataObj *d);
 	FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce);
+	FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses);
 	FreqDist(int src);
 	~FreqDist();
 	void DoPlot(anyOutput *o);
@@ -1938,8 +1956,11 @@ public:
 
 class GroupBars:public StackBar{
 public:
-	GroupBars(GraphObj *par, DataObj *d):StackBar(par, d){};
+	GroupBars(GraphObj *par, DataObj *d, int type):StackBar(par, d){mode = type;};
 	bool PropertyDlg();
+
+private:
+	int mode;
 };
 
 class Waterfall:public StackBar{
@@ -2283,6 +2304,7 @@ private:
 	RECT mrc;
 
 	void SetTick(long idx, double val, DWORD flags, char *txt);
+	void mkTimeAxis();
 	void CreateTicks();
 	void ManuTicks(double sa, double st, int n, DWORD flags);
 	void UpdateTicks();
@@ -2420,7 +2442,7 @@ public:
 	Axis **Axes;
 	char *filename;
 
-	Graph(GraphObj *par, DataObj *d, anyOutput *o);
+	Graph(GraphObj *par, DataObj *d, anyOutput *o, int style);
 	Graph(int src);
 	~Graph();
 	double GetSize(int select);
@@ -2441,7 +2463,7 @@ private:
 	DWORD ColDR, ColGR, ColGRL;
 	AxisDEF x_axis, y_axis;
 	FrmRect *frm_g, *frm_d;
-	bool dirty;
+	bool dirty, bDialogOpen;
 	POINT *tl_pts;
 	long tl_nPts;
 	ZoomDEF *zoom_def;
@@ -2731,7 +2753,7 @@ bool ShowLayers(GraphObj *root);
 void GetNewFill(FillDEF *oldfill);
 void ShowBanner(bool show);
 void RLPlotInfo();
-bool DoSpShSize(DataObj *dt);
+bool DoSpShSize(DataObj *dt, GraphObj *parent);
 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);
@@ -2770,6 +2792,7 @@ void WriteNatFloatToBuff(char *buff, double val);
 bool Txt2Flt(char *txt, double *val);
 void RmTrail(char *txt);
 double NiceValue(double fv);
+char *NiceTime(double val);
 char *Int2ColLabel(int nr, bool uc);
 char *mkCellRef(int row, int col);
 char *mkRangeRef(int r1, int c1, int r2, int c2);
@@ -2840,6 +2863,7 @@ void DoExportEps(GraphObj *g, char *FileName, DWORD flags);
 void DoExportTif(GraphObj *g, char *FileName, DWORD flags);
 
 //prototypes mfcalc.cpp
+void LockData(bool lockExec, bool lockWrite);
 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, 
@@ -2858,6 +2882,8 @@ bool Check_MRQerror();
 void SortArray(int n, double *vals);
 void SortArray2(int n, double *a1, double *a2);
 void SortFpArray(int n, lfPOINT *vals);
+double *randarr(double *v0, int n, long *seed);
+double *resample(double *v0, int n, long *seed);
 void spline(lfPOINT *v, int n, double *y2);
 double gammln(double x);
 double factrl(int n);
@@ -2883,6 +2909,12 @@ 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 weib_dist(double x, double shape, double scale);
+double weib_freq(double x, double shape, double scale);
+double cauch_dist(double x, double loc, double scale);
+double cauch_freq(double x, double loc, double scale);
+double logis_dist(double x, double loc, double scale);
+double logis_freq(double x, double loc, double scale);
 double ks_dist(int n, double d);
 void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2, 
 	bool bsorted, double *w, double *p);
@@ -2902,15 +2934,23 @@ double d_rank(int n, double *v, double v1);
 void crank(int n, double *w0, double *s);
 double d_spearman(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
 double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
-double d_regression(double *x, double *y, int n, char *dest, DataObj *data);
+double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
 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 *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);
+double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *results);
+double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
+bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss);
+bool bartlett(int n, int *nc, double *ss, double *chi2);
+bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P);
 double wprob(double w, double rr, double cc);
 double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p);
 double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p);
+int year2aday(int y);
+void add_date(rlp_datetime *base, rlp_datetime *inc);
+char *date2text(rlp_datetime *dt, char *fmt);
+double date2value(rlp_datetime *dt);
+void parse_datevalue(rlp_datetime *dt, double dv);
 bool date_value(char *desc, char *fmt, double *value);
 char *value_date(double dv, char *fmt);
 double now_today();
@@ -2920,9 +2960,13 @@ Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *text1, char *text2, char
 
 //prototypes reports.cpp
 void rep_anova(GraphObj *parent, DataObj *data);
+void rep_twanova(GraphObj *parent, DataObj *data);
+void rep_fmanova(GraphObj *parent, DataObj *data);
+void rep_twoway_anova(GraphObj *parent, DataObj *data);
 void rep_kruskal(GraphObj *parent, DataObj *data);
 void rep_samplestats(GraphObj *parent, DataObj *data);
 void rep_regression(GraphObj *parent, DataObj *data);
+void rep_robustline(GraphObj *parent, DataObj *data);
 void rep_twowaytable(GraphObj *parent, DataObj *data);
 void rep_compmeans(GraphObj *parent, DataObj *data);
 void rep_correl(GraphObj *parent, DataObj *data, int style);
diff --git a/RLPLOT.RC b/rlplot.rc
similarity index 94%
rename from RLPLOT.RC
rename to rlplot.rc
index 4fd0459..14eee0c 100755
--- a/RLPLOT.RC
+++ b/rlplot.rc
@@ -141,8 +141,15 @@ BEGIN
     	BEGIN
     		MENUITEM "&One Way Anova"			CM_REPANOV
     		MENUITEM "&Kruskal Wallis"			CM_REPKRUSKAL
+    		MENUITEM "&Two Way Anova",			CM_REPTWANOV
+    		MENUITEM "&Friedman Anova",			CM_REPFRIEDM
+    		MENUITEM "&Two Way /w Replica"		CM_REPTWANR
+    	END
+    	POPUP "&Regression"
+    	BEGIN
+    		MENUITEM "&Linear Regression"		CM_REPREGR
+    		MENUITEM "&Robust Line-Fit",		CM_ROBUSTLINE
     	END
-    	MENUITEM "&Regression"					CM_REPREGR
  		POPUP "C&orrelations"
 		BEGIN
 			MENUITEM "Correlation &Matrix"		CM_CORRELM
diff --git a/rlplot.spec b/rlplot.spec
index b63355e..b1d823b 100755
--- a/rlplot.spec
+++ b/rlplot.spec
@@ -1,5 +1,5 @@
 Name:      rlplot
-Version:   1.3
+Version:   1.4
 Release:   1
 Summary:   A plotting program to create high quality graphs from data.
 License:   GPL
@@ -23,7 +23,7 @@ Postscript (EPS).
 %setup -q -n %{name}
 
 %build
-make -e
+make
 
 %install
 rm -rf $RPM_BUILD_ROOT
@@ -41,6 +41,9 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_bindir}/exprlp
 
 %changelog
+* Fri Sep 14 2007 Reinhard Lackner
+- release 1.4
+
 * Sun Feb 25 2007 Reinhard Lackner
 - release 1.3
 
diff --git a/rlplot.spec b/rlplot.spec~
old mode 100755
new mode 100644
similarity index 100%
copy from rlplot.spec
copy to rlplot.spec~
diff --git a/spreadwi.cpp b/spreadwi.cpp
index 776d74b..c2f8921 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -160,11 +160,7 @@ SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
 		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;
@@ -286,7 +282,7 @@ 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() && 
+			if((g2 = new Graph(this, d, 0L, 0)) && g2->PropertyDlg() && 
 				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
 			else if(g2) DeleteGO(g2);
 			Undo.SetDisp(w);
@@ -342,6 +338,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 				filename = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 				return Command(CMD_SETSCROLL, 0L, w);
 				}
+			else ErrorBox("The selected file is not valid\nor not accessible!\n");
 			return false;
 		case CMD_OPEN:
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
@@ -357,7 +354,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			return false;
 		case CMD_ADDROWCOL:
-			if(DoSpShSize(d)) DoPlot(o);
+			if(DoSpShSize(d, this)) DoPlot(o);
 			return true;
 		case CMD_COL_MOUSE:
 			if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
@@ -448,7 +445,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 		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_SHPGUP:		case CMD_SHPGDOWN:
+		case CMD_SHPGUP:		case CMD_SHPGDOWN:		case CMD_HIDEMARK:
 			bDoColWidth = false;
 			return d->Command(cmd, tmpl, o);
 		case CMD_REDRAW:
@@ -460,9 +457,10 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 		case CMD_SETSCROLL:
 			HideTextCursor();						if(!(o->ActualSize(&currRC)))return false;
 			k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
-			d->GetSize(&i, &j);
+			d->GetSize(&i, &j);			o->MouseCursor(MC_WAIT, true);
 			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);
+			o->MouseCursor(MC_ARROW, true);
 			return true;
 		case CMD_PAGEUP:		case CMD_PAGEDOWN:
 			k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
@@ -489,7 +487,10 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 		case CMD_KILLFOCUS:
 			return true;
 		case CMD_TEXTSIZE:
-			if(tmpl)ssText.iSize = *((int*)tmpl);
+			if(tmpl && *((int*)tmpl) != ssText.iSize) {
+				Undo.ValInt(this, &ssText.iSize, UNDO_CONTINUE);
+				ssText.iSize = o->un2iy(defs.GetSize(SIZE_CELLTEXT));
+				}
 			return true;
 		case CMD_CONFIG:
 			if(defs.PropertyDlg()) return Command(CMD_REDRAW, 0L, o);
@@ -616,7 +617,7 @@ 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;
+	int row, col, width, height, ipad, mode;
 	double scale;
 	RECT rc, margin, margin_first;
 	POINT pp_pos, ss_pos, grid[3];
@@ -651,7 +652,7 @@ SpreadWin::PrintData(anyOutput *o)
 	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.Align = TXA_HCENTER | TXA_VCENTER;
 	td.Style = TXS_NORMAL;	td.iSize = 0;
 #ifdef _WINDOWS
 	tdp.iSize = iround(o->hres/6.0);
@@ -666,6 +667,8 @@ SpreadWin::PrintData(anyOutput *o)
 	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;
+	mode = 0;
+	if((nr * pch) < ((rc.bottom - rc.top - margin.top - margin.bottom)>>1)) mode = 1;
 	do {
 		k = (rc.right - margin.left - margin.right - pfw);
 		for(i = pgw = 0; pgw < k && (i+ss_pos.x) < nc; i++ ){
@@ -674,10 +677,12 @@ SpreadWin::PrintData(anyOutput *o)
 			}
 		if(pgw < k) {
 			cpp = i+1;
+			if(!mode && !ss_pos.x && pgw < (k>>1)) mode = 2;
 			}
 		else {
 			cpp = i-1;		pgw -= pcw;
 			}
+		mode = mode;
 		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;
@@ -763,11 +768,11 @@ SpreadWin::PrintData(anyOutput *o)
 		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)) {
+			if(mode == 2 && (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)) {
+			else if(mode == 1 && (margin.top + iy + pch + l*pch) < (rc.bottom - margin.bottom)) {
 				margin.top += iy;	margin.left = margin_first.left;
 				bContinue = true;
 				}
@@ -929,7 +934,11 @@ SpreadData::Init(int nRows, int nCols)
 		w = Disp->w;
 		if(w) {
 			CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
+#ifdef _WINDOWS
 			CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
+#else
+			CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/(defs.ss_txt *0.7)) + 2;
+#endif
 			if(CellHeight < 12)CellHeight = 19;		if(CellWidth < 40)CellWidth = 76;
 			FirstWidth = 32;						w->GetSize(&rc);
 			r_disp = (rc.bottom-rc.top)/CellHeight;
@@ -1304,6 +1313,9 @@ SpreadData::ChangeSize(int nCols, int nRows, bool bUndo)
 	bool RetVal = true;
 	
 	if(nCols == cCols && nRows == cRows) return true;
+	if(c_range){
+		free(c_range);	c_range = 0L;	EmptyClip();
+		}
 	if(bUndo) Undo.DataObject(Disp, w, this, 0L, 0L);
 	if(nRows && nRows < cRows) {
 		for (i = nRows; i < cRows; i++) {
@@ -1352,6 +1364,9 @@ SpreadData::DeleteCols()
 		InfoBox("No columns selected!");
 		return false;
 		}
+	if(c_range){
+		free(c_range);	c_range = 0L;	EmptyClip();
+		}
 	Undo.DataObject(Disp, w, this, 0L, 0L);
 	Undo.String(0L, &m_range, UNDO_CONTINUE);
 	if(!(ar = new AccRange(m_range))) return false;
@@ -1429,6 +1444,9 @@ SpreadData::InsertCols()
 		InfoBox("No columns selected!");
 		return false;
 		}
+	if(c_range){
+		free(c_range);	c_range = 0L;	EmptyClip();
+		}
 	Undo.DataObject(Disp, w, this, 0L, 0L);
 	Undo.String(0L, &m_range, UNDO_CONTINUE);
 	if(!(ar = new AccRange(m_range))) return false;
@@ -1498,6 +1516,9 @@ SpreadData::DeleteRows()
 		InfoBox("No rows selected!");
 		return false;
 		}
+	if(c_range){
+		free(c_range);	c_range = 0L;	EmptyClip();
+		}
 	Undo.DataObject(Disp, w, this, 0L, 0L);
 	Undo.String(0L, &m_range, UNDO_CONTINUE);
 	if(!(ar = new AccRange(m_range))) return false;
@@ -1575,6 +1596,9 @@ SpreadData::InsertRows()
 		InfoBox("No rows selected!");
 		return false;
 		}
+	if(c_range){
+		free(c_range);	c_range = 0L;	EmptyClip();
+		}
 	Undo.DataObject(Disp, w, this, 0L, 0L);
 	Undo.String(0L, &m_range, UNDO_CONTINUE);
 	if(!(ar = new AccRange(m_range))) return false;
@@ -1658,6 +1682,7 @@ SpreadData::DoPlot(anyOutput *o)
 	if(j >= (rc.right-rc.left))c_disp--;
 	Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
 	rc.top = w->MenuHeight;					rc.bottom = rc.top + CellHeight;
+	LockData(false, false);
 	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;
@@ -1694,6 +1719,7 @@ SpreadData::DoPlot(anyOutput *o)
 			}
 		delete (ar);
 		}
+	LockData(false, false);
 	if(c_range) InitCopy(0, 0L, w);			//move animated rectangle
 	if(!(w->ActualSize(&rc))) return;		
 	rc.bottom += CellHeight;		w->UpdateRect(&rc, false);
@@ -1961,6 +1987,18 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		if(PasteRange(cmd, (char*)tmpl)) 
 			return Disp->Command(CMD_SETSCROLL, 0L, w);
 		return false;
+	case CMD_HIDEMARK:
+		if(c_range){
+			free(c_range);	c_range = 0L;	return true;
+			}
+		return false;
+	case CMD_GETFILENAME:
+		if(!tmpl) return false;
+		if(rlw_file && rlw_file[0]) {
+			if(rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, rlw_file))return true;
+			else return false;
+			}
+		return false;
 	case CMD_ETRACC:
 		if(et_racc && tmpl && ((EditText*)tmpl)->parent != this) HideMark(false);
 		et_racc = (EditText*) tmpl;
@@ -2181,9 +2219,10 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		break;
 	case CMD_SET_CELLDIMS:
-		if(tmpl) {
-			FirstWidth = ((int*)tmpl)[0];	CellWidth = ((int*)tmpl)[1];
-			CellHeight = ((int*)tmpl)[2];
+		if(tmpl && (FirstWidth != ((int*)tmpl)[0] || CellWidth != ((int*)tmpl)[1] || CellHeight != ((int*)tmpl)[2])) {
+			Undo.ValInt(Disp, &FirstWidth, UNDO_CONTINUE);	Undo.ValInt(Disp, &CellWidth, UNDO_CONTINUE);
+			Undo.ValInt(Disp, &CellHeight, UNDO_CONTINUE);	FirstWidth = ((int*)tmpl)[0];
+			CellWidth = ((int*)tmpl)[1];					CellHeight = ((int*)tmpl)[2];
 			}
 		break;
 	case CMD_TEXTSIZE:
diff --git a/use_gui.cpp b/use_gui.cpp
index b78b780..2c45985 100755
--- a/use_gui.cpp
+++ b/use_gui.cpp
@@ -1,4 +1,4 @@
-//use_gui.cpp, Copyright 2000-2006 R.Lackner
+//use_gui.cpp, Copyright 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -33,6 +33,7 @@ extern GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
 extern Graph *CurrGraph;
 extern dragHandle *CurrHandle;
 extern UndoObj Undo;
+extern fmtText DrawFmtText;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Spread sheet buttons used for rows and columns
@@ -772,6 +773,7 @@ FrmRect::DoMark(anyOutput *o, bool mark)
 		if(maxRC) drag->Command(CMD_MAXRC, maxRC, o);
 		}
 	if(mark && drag){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6);
 		mo = GetRectBitmap(&mrc, o);
@@ -821,7 +823,7 @@ FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
 		case MOUSE_LBUP:
 			if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
 				o->ShowMark(this, MRK_GODRAW);
-				if(parent && parent->Id == GO_GRAPH) CurrGraph = (Graph*)parent;
+				if(!CurrGraph && parent && parent->Id == GO_GRAPH) CurrGraph = (Graph*)parent;
 				return true;
 				}
 			}
@@ -945,8 +947,18 @@ Label::AddChar(int ci, anyOutput *o)
 	char c, *txt1 = 0L;
 	int i, j, k;
 	GraphObj *golist[2];
+	DWORD flags;
 
-	if(!o) return false;
+	if(!o || (ci != 13 && ci < 32)) return false;
+	if(CheckMark()) {
+		Undo.String(this, &TextDef.text, 0L);
+		Undo.ValInt(this, &m1, UNDO_CONTINUE);
+		Undo.ValInt(this, &m2, UNDO_CONTINUE);
+		rlp_strcpy(TextDef.text+m1, (int)strlen(TextDef.text+m1)+1, TextDef.text+m2);
+		CursorPos = m1;		flags = UNDO_CONTINUE;
+		}
+	else flags = 0L;
+	m1 = m2 = -1;
 	if(ci == 13 && parent){		//CR
 		if(parent->Id == GO_MLABEL){
 			parent->Command(CMD_SETFOCUS, this, o);
@@ -965,8 +977,8 @@ Label::AddChar(int ci, anyOutput *o)
 	if(TextDef.text && TextDef.text[0]) i = (int)strlen(TextDef.text);
 	else i = 0;		if(CursorPos > i)CursorPos = i;
 	if(ci > 254) {
-		Undo.String(this, &TextDef.text, 0L);
-		Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+		Undo.String(this, &TextDef.text, flags);
+		Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
 		txt1 = (char*)malloc((i+12)*sizeof(char));
 		if(txt1) {
 			if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
@@ -986,8 +998,8 @@ Label::AddChar(int ci, anyOutput *o)
 	else if( ci > 31) c = (char)ci;
 	else return false;
 	if(!TextDef.text || CursorPos < 10 || c == ' ') {
-		Undo.String(this, &TextDef.text, 0L);
-		Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+		Undo.String(this, &TextDef.text, flags);
+		Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
 		}
 	txt1 = (char*)malloc((i+4)* sizeof(char));
 	if(txt1) {
@@ -1012,8 +1024,8 @@ Label::CalcCursorPos(int x, int y, anyOutput *o)
 	x1 = ((pts[3].x + pts[4].x)>>1);	y1 = ((pts[3].y + pts[4].y)>>1);
 	ix = ((j=(x1-x))*j);	ix += ((j=(y1-y))*j);	ix = isqr(ix);
 	for(i = 1,  x1 = 0; TextDef.text[i-1]; i++) {
-		if(fmt_txt)fmt_txt->oGetTextExtent(o, &x2, &h,i);
-		else o->oGetTextExtent(TextDef.text, i, &x2, &h);
+		DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+		DrawFmtText.oGetTextExtent(o, &x2, &h, i);
 		if(x1 <= ix && x2 >= ix) {
 			if((ix-x1) < (x2-ix)) CursorPos = i-1;
 			else CursorPos = i;
@@ -1096,6 +1108,7 @@ Axis::DoMark(anyOutput *o, bool mark)
 
 	if(axis->flags & AXIS_ANGULAR) {
 		if(mark) {
+			if(mo) DelBitmapClass(mo);					mo = 0L;
 			o->GetSize(&mrc);						mo = GetRectBitmap(&mrc, o);
 			memcpy(&mrkLine, &axline, sizeof(LineDEF));
 			mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;
@@ -1112,6 +1125,7 @@ Axis::DoMark(anyOutput *o, bool mark)
 		return;
 		}
 	if(mark){
+		if(mo) DelBitmapClass(mo);					mo = 0L;
 		memcpy(&mrc, &rDims, sizeof(RECT));
 		IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
 		mo = GetRectBitmap(&mrc, o);
@@ -1263,10 +1277,8 @@ Graph::ExecTool(MouseEvent *mev)
 				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.sx.fy = (lfp[1].fx - lfp[0].fx)/x;	scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
+					scale.sx.fy = (scale.sx.fy + scale.sy.fy) /2.0;		//preserve aspect ratio
 					scale.sy.fy = scale.sx.fy;
 					}
 				((Graph*)PasteObj)->GRect.Xmax -= ((Graph*)PasteObj)->GRect.Xmin;
@@ -1275,7 +1287,34 @@ Graph::ExecTool(MouseEvent *mev)
 				PasteObj->Command(CMD_SCALE, &scale, 0L);
 				Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
 				}
-			else DeleteGO(PasteObj);
+			else {
+				anyOutput *ScaleOut;
+				
+				if(ScaleOut = NewBitmapClass(10, 10, CurrDisp->hres, CurrDisp->vres)) {
+					PasteObj->parent = this;	PasteObj->DoPlot(ScaleOut);
+					switch(PasteObj->Id){
+					case GO_POLYLINE:		case GO_POLYGON:
+						IncrementMinMaxRect(&PasteObj->rDims, -(3*CurrDisp->un2ix(((polyline*)PasteObj)->pgLine.width)+3));
+						break;
+					case GO_BEZIER:
+						IncrementMinMaxRect(&PasteObj->rDims, 3);
+						break;
+						}
+					scale.sx.fx = CurrDisp->fix2un(-PasteObj->rDims.left);
+					scale.sy.fx = CurrDisp->fiy2un(-PasteObj->rDims.top);
+					PasteObj->Command(CMD_SCALE, &scale, 0L);
+					scale.sx.fx = lfp[0].fx;	scale.sy.fx = lfp[0].fy;	scale.sz.fx = 0.0;
+					if(abs(pc.x -pl.x) > 8 && abs(pc.y -pl.y) > 8) {
+						x = CurrDisp->fix2un(PasteObj->rDims.right - PasteObj->rDims.left);
+						y = CurrDisp->fiy2un(PasteObj->rDims.bottom - PasteObj->rDims.top);
+						scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x;	
+						scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
+						}
+					PasteObj->Command(CMD_SCALE, &scale, 0L);
+					delete ScaleOut;
+					}
+				Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
+				}
 			PasteObj = 0L;
 			ToolMode = TM_STANDARD;			CurrDisp->MouseCursor(MC_ARROW, false);
 			break;
@@ -1344,15 +1383,18 @@ Graph::ExecTool(MouseEvent *mev)
 				memcpy(&pl, &pc, sizeof(POINT));
 				line[1].x = pc.x = mev->x;		line[1].y = pc.y = mev->y;
 				line[0].x = pl.x;				line[0].y = pl.y;
-				CurrDisp->ShowLine(line, 2, color);
 				AddToPolygon(&tl_nPts, tl_pts, &pc);
+#ifdef _WINDOWS
+				CurrDisp->ShowLine(line, 2, color);
+#else
+				CurrDisp->ShowLine(tl_pts, tl_nPts, color);
+#endif
 				return true;
 				}
 			break;
 			}
 		break;
-	case TM_POLYLINE:
-	case TM_POLYGON:
+	case TM_POLYLINE:	case TM_POLYGON:
 		switch (mev->Action) {
 		case MOUSE_LBDOWN:
 			if(!tl_pts) {
@@ -1404,7 +1446,6 @@ Graph::ExecTool(MouseEvent *mev)
 					else i = NumPlots;
 					Undo.SetGO(this, &Plots[i], ToolMode == TM_POLYLINE ?
 						new polyline(this, data, lfp, (int)tl_nPts) :
-//						(GraphObj*) new Bezier(this, data, lfp, (int)tl_nPts) :
 						(GraphObj*) new polygon(this, data, lfp, (int)tl_nPts), 0L);
 					if(Plots[i]){
 						NumPlots = i+1;
@@ -1476,9 +1517,9 @@ Graph::ExecTool(MouseEvent *mev)
 				else new_go = 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
+					NumPlots = i+1;				CurrDisp->HideMark();
+					Plots[i]->DoPlot(CurrDisp);								//init
+					CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);		//edit
 					Plots[i]->moveable = 1;
 					bModified = true;
 					}

-- 
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