[rlplot] 09/23: Imported Upstream version 1.1.2

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


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

tille pushed a commit to branch master
in repository rlplot.

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

    Imported Upstream version 1.1.2
---
 Axes.cpp        |    2 +-
 Fileio.cpp      |   12 +-
 Makefile        |   17 +-
 Makefile.win    |   97 ---
 ODbuttons.cpp   |   20 +-
 PlotObs.cpp     |   74 ++-
 PropertyDlg.cpp |  693 +++++++++++----------
 QT_Spec.cpp     |  196 +++---
 QT_Spec.h       |    2 +
 RLPLOT.RC       |   78 +--
 TheDialog.cpp   |   65 +-
 TheDialog.h     |    3 +-
 UtilObj.cpp     |   15 +-
 Utils.cpp       |    4 +-
 Version.h       |    2 +-
 WinSpec.cpp     |   78 ++-
 WinSpec.h       |    2 +-
 exprlp.cpp      |  353 +----------
 menu.h          |   97 +++
 mfcalc.cpp      |   85 ++-
 mfcalc.y        |   69 ++-
 no_gui.cpp      |  550 +++++++++++++++++
 reports.cpp     |  613 +++++++++++++++++++
 rlp_math.cpp    |  303 +++++++++-
 rlplot.cpp      | 1786 +++----------------------------------------------------
 rlplot.h        |   16 +-
 spreadwi.cpp    |   32 +-
 use_gui.cpp     | 1656 +++++++++++++++++++++++++++++++++++++++++++++++++++
 28 files changed, 4176 insertions(+), 2744 deletions(-)

diff --git a/Axes.cpp b/Axes.cpp
index bc5a4a0..b446a0c 100755
--- a/Axes.cpp
+++ b/Axes.cpp
@@ -1294,7 +1294,7 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
-	case CMD_CAN_DELETE:
+	case CMD_CAN_CLOSE:
 		if(axis->owner == (void*)this) return true;
 		return false;
 	case CMD_DROP_LABEL:
diff --git a/Fileio.cpp b/Fileio.cpp
index edfb6f6..fc7a5d5 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -221,7 +221,7 @@ int WriteEscString(char *txt, char *buff, int cb)
 			}
 		if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
 		if(j > lim && (l-i) > 5) {
-			j += sprintf(esc_str+j, "\"\n   \"");
+			j += sprintf(esc_str+j, "\"\\\n   \"");
 			lim += 60;
 			}
 		}
@@ -934,7 +934,12 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 		if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
 			// object accepted
 			}
-		else if(!(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
+		else if(go->Id < GO_GRAPH 
+			&& !(root->Command(CMD_DROP_PLOT, (void *)go, 0L))){
+			DeleteGO(go);	go = 0L;
+			}
+		else if(go->Id >= GO_GRAPH 
+			&& !(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
 			DeleteGO(go);	go = 0L;
 			}
 		if(go) go->Command(CMD_FILENAME, name, 0L);
@@ -3583,7 +3588,8 @@ DefsRW::FileIO(int rw)
 		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
 		{"fmt_date", typTEXT, &defs.fmt_date, 0L},
 		{"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
-		{"fmt_time", typTEXT, &defs.fmt_time, 0L},
+		{"fmt_time", typTEXT, &defs.fmt_time, 0L},
+		{"curr_path", typTEXT, &defs.currPath, 0L},
 		{"File1", typTEXT, &defs.File1, 0L},
 		{"File2", typTEXT, &defs.File2, 0L},
 		{"File3", typTEXT, &defs.File3, 0L},
diff --git a/Makefile b/Makefile
index 46f1ebf..5c4223d 100755
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Makefile, Copyright 2002-2004 R.Lackner
+# Makefile, Copyright 2002-2006 R.Lackner
 # 
 #
 #    This file is part of RLPlot.
@@ -30,11 +30,12 @@ X11LIBS = -lX11 -lm
 SRCDIR = ./
 
 GENOBJ = exprlp.o rlplot.o Output.o Utils.o UtilObj.o\
- Fileio.o Export.o PlotObs.o Axes.o mfcalc.o rlp_math.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
+ Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o use_gui.o\
+ reports.o
 
 all:
 	make rlplot QTDIR=$(QTDIR) 
@@ -108,10 +109,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 $<
 
+reports.o: $(SRCDIR)reports.cpp $(SRCDIR)rlplot.h
+	$(CC) $(CFLAGS) -o $@ -c $<
 
 
 
diff --git a/Makefile.win b/Makefile.win
deleted file mode 100755
index f5ca7d1..0000000
--- a/Makefile.win
+++ /dev/null
@@ -1,97 +0,0 @@
-# Makefile.win, Copyright 2002-2004 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
-#
-CC = cl.exe
-CFLAGS = /nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD
-LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib\
- shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
-SRCDIR =
-
-GENOBJ = exprlp.obj rlplot.obj Output.obj Utils.obj UtilObj.obj\
- FileIO.obj Export.obj PlotObs.obj Axes.obj mfcalc.obj rlp_math.obj
-
-OBJECTS = WinSpec.obj Output.obj Utils.obj UtilObj.obj\
- TheDialog.obj rlplot.obj FileIO.obj PropertyDlg.obj spreadwi.obj\
- Export.obj PlotObs.obj ODbuttons.obj Axes.obj mfcalc.obj rlp_math.obj
-
-RLPlot: $(OBJECTS) RLPLOT.res
-	link.exe $(LIBS) /nologo /subsystem:windows /incremental:no /pdb:"RLPlot.pdb"\
- /machine:I386 /out:"RLPlot.exe" $(OBJECTS) RLPLOT.res
- 
-exprlp: $(GENOBJ)
-	$(CC) -o exprlp $(GENOBJ)
-
-clean:
-	del *.obj
-	del *.pch
-	del *.idb
-	del *.res
-
-####### Compile
-RLPLOT.res: $(SRCDIR)RLPLOT.RC
-	rc.exe /d "NDEBUG" $(SRCDIR)RLPLOT.RC
-
-mfcalc.obj: $(SRCDIR)mfcalc.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)mfcalc.cpp
-
-rlp_math.obj: $(SRCDIR)rlp_math.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)rlp_math.cpp
-
-exprlp.obj: $(SRCDIR)exprlp.cpp
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)exprlp.cpp
-
-WinSpec.obj: $(SRCDIR)WinSpec.cpp $(SRCDIR)WinSpec.h $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)WinSpec.cpp
-
-Output.obj: $(SRCDIR)Output.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Output.cpp
-
-Utils.obj: $(SRCDIR)Utils.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Utils.cpp
-
-UtilObj.obj: $(SRCDIR)UtilObj.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)UtilObj.cpp
-
-TheDialog.obj: $(SRCDIR)TheDialog.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)TheDialog.cpp
-
-rlplot.obj: $(SRCDIR)rlplot.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)rlplot.cpp
-
-FileIO.obj: $(SRCDIR)FileIO.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)FileIO.cpp
-
-PropertyDlg.obj: $(SRCDIR)PropertyDlg.cpp $(SRCDIR)rlplot.h $(SRCDIR)TheDialog.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)PropertyDlg.cpp
-
-spreadwi.obj: $(SRCDIR)spreadwi.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)spreadwi.cpp
-
-Export.obj: $(SRCDIR)Export.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Export.cpp
-
-PlotObs.obj: $(SRCDIR)PlotObs.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)PlotObs.cpp
-
-ODbuttons.obj: $(SRCDIR)ODbuttons.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)ODbuttons.cpp
-	
-Axes.obj: $(SRCDIR)Axes.cpp $(SRCDIR)rlplot.h
-	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Axes.cpp
-
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index e328796..14cd26f 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -651,7 +651,7 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		iy = (rec->top +rec->bottom)>>1;
 		switch(id) {
 		case 560:	case 561:	case 562:	case 563:	case 564:		//3D axes
-		case 565:	case 566:
+		case 565:	case 566:	case 567:
 			OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
 			break;
 		default:
@@ -1103,10 +1103,8 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 			td.Align = TXA_HCENTER | TXA_VTOP;
 			td.Mode = TXM_TRANSPARENT;
 			if(id == 565) {
-				td.Style = TXS_NORMAL;
-				td.ColTxt = 0x00c00000L;
-				o->SetTextSpec(&td);
-				o->oTextOut(ix, iy+4, "f(x,z)", 0);
+				td.Style = TXS_NORMAL;			td.ColTxt = 0x00c00000L;
+				o->SetTextSpec(&td);			o->oTextOut(ix, iy+4, "f(x,z)", 0);
 				}
 			else {
 				td.Style = TXS_BOLD;
@@ -1117,6 +1115,18 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 				}
 			o->SetTextSpec(&otd);
 			break;
+		case 567:
+			o->SetLine(&bLine);			if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
+			pts[0].x = ix-10;			pts[0].y = iy+4;
+			pts[1].x = ix-6;			pts[1].y = iy+10;
+			pts[2].x = ix-16;			pts[2].y = iy+8;
+			o->oPolygon(pts, 3, 0L);
+			pts[2].x = ix+2;		pts[2].y = iy-10;		o->oPolygon(pts, 3, 0L);
+			pts[0].x = ix+10;		pts[0].y = iy-12;		o->oPolygon(pts, 3, 0L);
+			pts[2].x = ix+2;		pts[2].y = iy+14;		o->oPolygon(pts, 3, 0L);
+			pts[1].x = ix+12;		pts[1].y = iy+4;		o->oPolygon(pts, 3, 0L);
+			pts[0].x = ix+16;		pts[0].y = iy+12;		o->oPolygon(pts, 3, 0L);
+			break;
 			}
 		o->UpdateRect(rec, false);
 		break;
diff --git a/PlotObs.cpp b/PlotObs.cpp
index 9a8324b..926bec2 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -994,16 +994,16 @@ FreqDist::Command(int cmd, void *tmpl, anyOutput *o)
 			((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
 			((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
 			return true;
-		case CMD_DROP_GRAPH:
-			if(tmpl && plots && nPlots >1) {
-				if(plots[1]) DeleteGO(plots[1]);
-				plots[1] = (GraphObj*)tmpl;		dirty = true;		plots[1]->parent = this;
-				plots[1]->Command(CMD_SET_DATAOBJ, curr_data, o);
-				Command(CMD_AUTOSCALE, 0L, o);
-				return true;
-				}
-			return false;
 			}
+	case CMD_DROP_PLOT:		case CMD_DROP_GRAPH:
+		if(tmpl && plots && nPlots >1) {
+			if(plots[1]) DeleteGO(plots[1]);
+			plots[1] = (GraphObj*)tmpl;		dirty = true;		plots[1]->parent = this;
+			plots[1]->Command(CMD_SET_DATAOBJ, curr_data, o);
+			Command(CMD_AUTOSCALE, 0L, o);
+			return true;
+			}
+		return false;
 		}
 	return false;
 }
@@ -1013,7 +1013,7 @@ FreqDist::ProcData(int sel)
 {
 	AccRange *ar;
 	int nv, i, j, r, c, ncl, *f_data, cb;
-	double min = HUGE_VAL, max = -HUGE_VAL, sum, mean, sd, tmp, d, *s_data;
+	double min = HUGE_VAL, max = -HUGE_VAL, sum, mean, sd, tmp, *s_data, *t_data;
 	Bar **bars = 0L;
 	char *fo;
 
@@ -1021,18 +1021,22 @@ FreqDist::ProcData(int sel)
 	if(curr_data) delete(curr_data);
 	if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
 		nv = ar->CountItems();			ar->GetFirst(&c, &r);
-		if(!(s_data = (double*)malloc(nv * sizeof(double)))) {
+		if(!(s_data = (double*)malloc(nv * sizeof(double))) 
+			|| !(t_data = (double*)malloc(nv * sizeof(double)))) {
 			delete(ar);					return;
 			}
 		for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetValue(r, c, &tmp)) {
-			sum+=tmp;	s_data[nv++] = tmp;
-			}
-		mean = sum / ((double)nv);		delete(ar);
-		for(sum = 0.0, j = 0; j < nv; j++){
-			if(s_data[j] > max) max = s_data[j];	if(s_data[j] < min) min = s_data[j];
-			sum += ((d = (s_data[j] - mean)) * d);
+			if(tmp > max) max = tmp;	if(tmp < min) min = tmp;
+			s_data[nv] = tmp;
+			switch (type & 0xff){
+			case 2:		t_data[nv] = log(tmp);	break;
+			default:	t_data[nv] = tmp;		break;
+				}
+			nv++;
 			}
-		sd = sqrt(sum/((double)nv));
+		delete(ar);
+		d_variance(nv, t_data, &mean, &sd);
+		sd = sqrt(sd/((double)(nv-1)));
 		step = fabs(step);
 		if(sel == -1) {
 			start = min;	step = (max - min)/(step != 0.0 ? step : 7.0);
@@ -1060,7 +1064,7 @@ FreqDist::ProcData(int sel)
 				bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i);
 				}
 			}
-		free(s_data);		free(f_data);
+		free(s_data);		free(t_data);		free(f_data);
 		if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars))){
 			plots[0]->Command(CMD_BAR_FILL, &BarFill, 0L);
 			plots[0]->SetColor(COL_BAR_LINE, BarLine.color);
@@ -1070,15 +1074,20 @@ FreqDist::ProcData(int sel)
 			plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
 			plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
 			}
-		if(type && (fo = (char*)malloc(1000))) {
+		if((type & 0xff) && (fo = (char*)malloc(1000))) {
 			cb = sprintf(fo, "[1=Function]\n");
 			cb += sprintf(fo+cb,"x1= %g\n", min);
 			cb += sprintf(fo+cb,"x2= %g\n", max);
 			cb += sprintf(fo+cb,"xstep= %g\n", (max-min)/100.0);
 			cb += sprintf(fo+cb,"Line= 0.4 6 0x000000ff 0x0\n");
-			cb += sprintf(fo+cb,"f_xy=\"A=%g; SD=%g; M=%g\\n", nv*step, sd, mean);
-			cb += sprintf(fo+cb,"ex=(x-M)/SD; ex=-0.5*ex*ex\\n");
-			cb += sprintf(fo+cb,"y=(A/(SD*2.5066283))*exp(ex)\\n\"\n");
+			switch (type & 0xff){
+			case 2:
+				cb += sprintf(fo+cb,"f_xy=\"y=%g*lognormfreq(x,%g,%g)\"",nv*step, mean, sd);
+				break;
+			default:
+				cb += sprintf(fo+cb,"f_xy=\"y=%g*normfreq(x,%g,%g)\"",nv*step, mean, sd);
+				break;
+				}
 			OpenGraph(this, 0L, (unsigned char *)fo, false);
 			free(fo);
 			}
@@ -3331,6 +3340,17 @@ Ribbon::Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr)
 	if(zr) ssRefZ = strdup(zr);
 }
 
+Ribbon::Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo)
+	:Plot(par, d)
+{
+	int i;
+
+	FileIO(INIT_VARS);		Id = GO_RIBBON;		type = 3;
+	planes = (Plane3D**)go;						nPlanes = ngo;
+	for(i = 0; i < ngo; i++) planes[i]->parent = this;
+}
+
+
 Ribbon::Ribbon(int src):Plot(0L, 0L)
 {
 	FileIO(INIT_VARS);
@@ -3554,6 +3574,9 @@ Ribbon::CreateObs()
 			nPlanes = i-1;		nVal = i;
 			}
 		break;
+	case 3:
+		//external creation of planes;
+		break;
 		}
 	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
 }
@@ -4872,8 +4895,9 @@ Plot3D::SortObj()
 			}
 		i = l;					j = l << 1;
 		while(j <= ir) {
-			if(j < ir && dispObs[j]->Zmin < dispObs[j+1]->Zmin) ++j;
-			if(rra->Zmin < dispObs[j]->Zmin) {
+			if(j < ir && (dispObs[j]->Zmin < dispObs[j+1]->Zmin
+				|| (dispObs[j]->Zmin == dispObs[j+1]->Zmin && dispObs[j]->Zmax < dispObs[j+1]->Zmax))) ++j;
+			if(rra->Zmin < dispObs[j]->Zmin || (rra->Zmin == dispObs[j]->Zmin && rra->Zmax < dispObs[j]->Zmax)) {
 				dispObs[i] = dispObs[j];
 				j += (i = j);
 				}
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index 4d0147e..d5df21c 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -1820,33 +1820,38 @@ Sphere::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // properties of 3D plane
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Plane3D_DlgTmpl = 
+	"1,2,,DEFAULT, PUSHBUTTON,1,115,10,55,12\n"
+	"2,3,,,PUSHBUTTON,2,115,25,55,12\n"
+	"3,4,,,PUSHBUTTON,-2,115,40,55,12\n"
+	"4,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"10,,100,ISPARENT | CHECKED,SHEET,3,5,10,105,85\n"
+	"100,101,,,RTEXT,4,15,30,36,8\n"
+	"101,102,,,EDVAL1,5,53,30,25,10\n"
+	"102,103,,,LTEXT,-3,80,30,15,8\n"
+	"103,104,,,RTEXT,6,15,42,36,8\n"
+	"104,105,,OWNDIALOG,COLBUTT,7,53,42,25,10\n"
+	"105,106,,,RTEXT,8,15,54,36,8\n"
+	"106,200,,OWNDIALOG,SHADE3D,9,53,54,25,10\n"
+	"200,,201,CHECKED,GROUP,0,0,0,0,0\n"
+	"201,202,,,RTEXT,10,15,66,36,8\n"
+	"202,203,,,INCDECVAL1,11,53,66,25,10\n"
+	"203,204,,,LTEXT,-10,80,66,5,8\n"
+	"204,205,,,RTEXT,12,15,78,36,8\n"
+	"205,206,,,EDVAL1,13,53,78,25,10\n"
+	"206,,,LASTOBJ,LTEXT,14,80,78,40,8";
+
 bool
 Plane3D::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 27, 10, "Plane"};
 	double rb_width = 0.0, rb_z = 0.0;
 	FillDEF newFill;
-	DlgInfo PlaneDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to PLANE", 115, 10, 55, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 115, 25, 55, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 115, 40, 55, 12},
-		{4, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{10, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 105, 85},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"line width", 15, 30, 36, 8},
-		{101, 102, 0, 0x0L, EDVAL1, &Line.width, 53, 30, 25, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 80, 30, 15, 8},
-		{103, 104, 0, 0x0L, RTEXT, (void*)"line color", 15, 42, 36, 8},
-		{104, 105, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 53, 42, 25, 10},
-		{105, 106, 0, 0x0L, RTEXT, (void*)"fill color", 15, 54, 36, 8},
-		{106, 200, 0, OWNDIALOG, SHADE3D, &newFill, 53, 54, 25, 10},
-		{200, 0, 201, CHECKED, GROUP, NULL, 0, 0, 0, 0},
-		{201, 202, 0, 0x0L, RTEXT, (void*)"ribbon width", 15, 66, 36, 8},
-		{202, 203, 0, 0x0L, INCDECVAL1, &rb_width, 53, 66, 25, 10},
-		{203, 204, 0, 0x0L, LTEXT, (void*)"%", 80, 66, 5, 8},
-		{204, 205, 0, 0x0L, RTEXT, (void*)"ribbon pos.", 15, 78, 36, 8},
-		{205, 206, 0, 0x0L, EDVAL1, &rb_z, 53, 78, 25, 10},
-		{206, 0, 0, 0x0L, LTEXT, (void*)"[z-data]", 80, 78, 40, 8},
-		{800, 0, 0, LASTOBJ, 0L, 0, 0, 0, 0}};
+	void *dyndata[] = {(void*)"Apply to PLANE", (void*)"Apply to PLOT", (void*)&tab1,
+		 (void*)"line width",  (void*)&Line.width, (void*)"line color", (void *)&Line.color,
+		 (void*)"fill color", (void*)&newFill, (void*)"ribbon width", (void*)&rb_width,
+		 (void*)"ribbon pos.", (void*)&rb_z,  (void*)"[z-data]"};
+	DlgInfo *PlaneDlg = CompileDialog(Plane3D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res;
@@ -1865,9 +1870,10 @@ Plane3D::PropertyDlg()
 	Dlg = new DlgRoot(PlaneDlg);
 	Dlg->GetValue(101, &o_lsize);		Dlg->GetValue(202, &o_rbw);
 	Dlg->GetValue(205, &o_rbz);
-	if(parent && ((parent->Id==GO_RIBBON && parent->type == 2) || parent->Id==GO_GRID3D))
+	if(parent && ((parent->Id==GO_RIBBON && parent->type > 1) || parent->Id==GO_GRID3D))
 		Dlg->ShowItem(200, false);								//paravent plot
-	if(parent->name) sprintf(TmpTxt, "Plane of %s", parent->name);
+	if(parent->Id == GO_RIBBON && parent->type >2) sprintf(TmpTxt, "3D Surface Properties");
+	else if(parent->name) sprintf(TmpTxt, "Plane of %s", parent->name);
 	else strcpy(TmpTxt, "Plane properties");
 	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x0L);
 	do{
@@ -2023,47 +2029,55 @@ Brick::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Properties of arrow in 3D space
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Arrow3D_DlgTmpl =
+	"1,2,,DEFAULT, PUSHBUTTON,1,100,10,57,12\n"
+	"2,3,,,PUSHBUTTON,2,100,25,57,12\n"
+	"3,4,,,PUSHBUTTON,-2,100,40,57,12\n"
+	"4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,90,100\n"
+	"6,7,200,ISPARENT,SHEET,4,5,10,90,100\n"
+	"7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
+	"100,101,,,RTEXT,6,15,40,28,8\n"
+	"101,102,,,EDVAL1,7,46,40,25,10\n"
+	"102,103,,,LTEXT,-3,73,40,20,8\n"
+	"103,104,,,RTEXT,8,15,52,28,8\n"
+	"104,105,,,EDVAL1,9,46,52,25,10\n"
+	"105,106,,,LTEXT,-3,73,52,20,8\n"
+	"106,107,,,RTEXT,10,15,70,28,8\n"
+	"107,108,,,EDVAL1,11,46,70,25,10\n"
+	"108,109,,,LTEXT,-3,73,70,20,8\n"
+	"109,110,,,RTEXT,-11,15,82,28,8\n"
+	"110,,,OWNDIALOG,COLBUTT,12,46,82,25,10\n"
+	"200,201,,TOUCHEXIT,RADIO1,13,15,40,60,8\n"
+	"201,202,,TOUCHEXIT,RADIO1,14,15,55,60,8\n"
+	"202,,,TOUCHEXIT,RADIO1,15,15,70,60,8\n"
+	"300,301,,,RTEXT,-12,10,25,28,8\n"
+	"301,302,,,EDVAL1,16,46,25,35,10\n"
+	"302,303,,,RTEXT,-13,10,36,28,8\n"
+	"303,304,,,EDVAL1,17,46,36,35,10\n"
+	"304,305,,,RTEXT,-14,10,47,28,8\n"
+	"305,306,,,EDVAL1,18,46,47,35,10\n"
+	"306,307,,,RTEXT,19,10,60,28,8\n"
+	"307,308,,,EDVAL1,20,46,60,35,10\n"
+	"308,309,,,RTEXT,-5,10,71,28,8\n"
+	"309,310,,,EDVAL1,21,46,71,35,10\n"
+	"310,311,,,RTEXT,-6,10,82,28,8\n"
+	"311,312,,,EDVAL1,22,46,82,35,10\n"
+	"312,,,LASTOBJ,CHECKBOX,23,16,95,70,8";
+
 bool
 Arrow3D::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 29, 10, "Arrow"};
 	TabSHEET tab2 = {29, 59, 10, "Type"};
 	TabSHEET tab3 = {59, 90, 10, "Edit"};
-	DlgInfo ArrowDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to ARROW", 100, 10, 57, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 57, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 57, 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, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
-		{7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
-		{101, 102, 0, 0x0L, EDVAL1, &cw, 46, 40, 25, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
-		{103, 104, 0, 0x0L, RTEXT, (void*)"length", 15, 52, 28, 8},
-		{104, 105, 0, 0x0L, EDVAL1, &cl, 46, 52, 25, 10},
-		{105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 52, 20, 8},
-		{106, 107, 0, 0x0L, RTEXT, (void*)"line width", 15, 70, 28, 8},
-		{107, 108, 0, 0x0L, EDVAL1, &Line.width, 46, 70, 25, 10},
-		{108, 109, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 70, 20, 8},
-		{109, 110, 0, 0x0L, RTEXT, (void*)"color", 15, 82, 28, 8},
-		{110, 0, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 46, 82, 25, 10},
-		{200, 201, 0, TOUCHEXIT, RADIO1, (void*)"line only", 15, 40, 60, 8},
-		{201, 202, 0, TOUCHEXIT, RADIO1, (void*)"arrow with lines", 15, 55, 60, 8},
-		{202, 0, 0, TOUCHEXIT, RADIO1, (void*)"filled arrow", 15, 70, 60, 8},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 25, 28, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &fPos2.fx, 46, 25, 35, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 36, 28, 8},
-		{303, 304, 0, 0x0L, EDVAL1, &fPos2.fy, 46, 36, 35, 10},
-		{304, 305, 0, 0x0L, RTEXT, (void*)"z-value", 10, 47, 28, 8},
-		{305, 306, 0, 0x0L, EDVAL1, &fPos2.fz, 46, 47, 35, 10},
-		{306, 307, 0, 0x0L, RTEXT, (void*)"origin x", 10, 60, 28, 8},
-		{307, 308, 0, 0x0L, EDVAL1, &fPos1.fx, 46, 60, 35, 10},
-		{308, 309, 0, 0x0L, RTEXT, (void*)" y", 10, 71, 28, 8},
-		{309, 310, 0, 0x0L, EDVAL1, &fPos1.fy, 46, 71, 35, 10},
-		{310, 311, 0, 0x0L, RTEXT, (void*)" z", 10, 82, 28, 8},
-		{311, 312, 0, 0x0L, EDVAL1, &fPos1.fz, 46, 82, 35, 10},
-		{312, 0, 0, LASTOBJ, CHECKBOX, (void*)"set common origin", 16, 95, 70, 8}};
+	void *dyndata[] = {(void*)"Apply to ARROW", (void*)"Apply to PLOT", (void*)&tab1,
+		(void*)&tab2, (void*)&tab3, (void*)"cap width", (void*)&cw, (void*)"length",
+		(void*)&cl, (void*)"line width", (void*)&Line.width, (void *)&Line.color,
+		(void*)"line only", (void*)"arrow with lines", (void*)"filled arrow",
+		(void*)&fPos2.fx, (void*)&fPos2.fy, (void*)&fPos2.fz, (void*)"origin x",
+		(void*)&fPos1.fx, (void*)&fPos1.fy, (void*)&fPos1.fz, (void*)"set common origin"};
+	DlgInfo *ArrowDlg = CompileDialog(Arrow3D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	fPOINT3D o_pos1, o_pos2, n_pos1, n_pos2;
@@ -2144,9 +2158,7 @@ Arrow3D::PropertyDlg()
 			}
 		break;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
-	return bRet;
+	CloseDlgWnd(hDlg);	delete Dlg;		free(ArrowDlg);		return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2263,10 +2275,10 @@ Label::PropertyDlg()
 		{313, 314, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 144, 64, 10, 8},
 		{314, 315, 0, 0x0L, LTEXT, (void*)"hot spot (text alignment):", 10, 85, 80, 8},
 		{315, 0, 0, 0x0L, TXTHSP, (void*)&TextDef.Align, 97, 78, 45, 25},
-		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 45, 15, 15},
-		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 60, 15, 15},
-		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 75, 15, 15},
-		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 90, 15, 15}};
+		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 45, 15, 15},
+		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 60, 15, 15},
+		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 75, 15, 15},
+		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 90, 15, 15}};
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, i, c_style, c_font;
@@ -2913,7 +2925,7 @@ PlotScatt::CreateBarChart()
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
-	int k, l, n, ic, res, width, height;
+	int k, l, n, ic, res;
 	double x, y;
 	AccRange *rY = 0L;
 	LineDEF Line;
@@ -2924,11 +2936,10 @@ PlotScatt::CreateBarChart()
 	memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
-	data->GetSize(&width, &height);
-	sprintf(TmpTxt, "a1:a%d", height);
+	UseRangeMark(data, 1, TmpTxt);
 	if(!(Dlg = new DlgRoot(BarDlg)))return false;
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
-	hDlg = CreateDlgWnd("Simple bar chart", 50, 50, 370, 280, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Simple Bar Chart", 50, 50, 370, 280, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -3415,7 +3426,7 @@ FreqDist::PropertyDlg()
 		{100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
 		{101, 102, 0, 0x0L, RANGEINPUT, TmpTxt, 10, 38, 110, 10},
 		{102, 103, 120, ISPARENT | CHECKED, GROUPBOX, (void*)" classes ", 10, 55, 110, 42},
-		{103, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" plot function ", 10, 102, 110, 17}, 
+		{103, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" plot distribution ", 10, 102, 110, 17}, 
 		{120, 121, 0, CHECKED, RADIO1, (void*)"create", 15, 60, 30, 9},
 		{121, 122, 0, 0x0L, EDTEXT, (void*)"7", 47, 60, 15, 10},
 		{122, 123, 0, 0x0L, LTEXT, (void*)"classes and bars", 64, 60, 35, 8},
@@ -3423,20 +3434,22 @@ FreqDist::PropertyDlg()
 		{124, 125, 0, 0x0L, EDTEXT, 0L, 65, 72, 50, 10},
 		{125, 126, 0, 0x0L, RTEXT, (void*)"starting at", 15, 84, 47, 8},
 		{126, 0, 0, 0x0L, EDTEXT, 0L, 65, 84, 50, 10},
-		{150, 0, 0, ISRADIO, CHECKBOX, (void*)" normal dist.", 15, 107, 30, 8},
+		{150, 151, 0, ISRADIO, CHECKBOX, (void*)" normal", 15, 107, 30, 8},
+		{151, 0, 0, ISRADIO, CHECKBOX, (void*)" log-normal", 65, 107, 30, 8},
 		{200, 0, 210, ISPARENT | CHECKED, GROUPBOX, (void*)" bar style ", 10, 27, 110, 61}, 
 		{210, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 34, 90, 50},
 		{800, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false;
-	int res, width, height;
+	int res;
+	char *mrk;
 
 	if(!parent || !data) return false;
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
-	data->GetSize(&width, &height);
-	sprintf(TmpTxt, "a1:a%d", height);
+	if(data->Command(CMD_GETMARK, &mrk, 0L)) strcpy(TmpTxt, mrk);
+	else TmpTxt[0] = 0;
 	if(!(Dlg = new DlgRoot(FreqDlg)))return false;
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 280, Dlg, 0x0L);
@@ -3452,8 +3465,9 @@ FreqDist::PropertyDlg()
 				if(ssRef) free(ssRef);
 				ssRef = strdup(TmpTxt);
 				}
-			type = 0;
 			if(Dlg->GetCheck(150)) type = 1;
+			else if(Dlg->GetCheck(151)) type = 2;
+			else type = 0;
 			break;
 			}
 		}while (res <0);
@@ -3778,12 +3792,12 @@ PolarPlot::AddPlot()
 		{203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 70, 20, 20, 20},
 		{204, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 90, 20, 20, 20},
 		{210, 211, 0, 0x0L, LTEXT, (void*)"range for x-data (circular or angular data)", 10, 50, 50, 8},
-		{211, 212, 0, 0x0L, EDTEXT, (void*)text1, 20, 62, 100, 10},
+		{211, 212, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 62, 100, 10},
 		{212, 213, 0, 0x0L, LTEXT, (void*)"range for y-data (radial data)", 10, 75, 50, 8},
-		{213, 0, 0, LASTOBJ, EDTEXT, (void*)text2, 20, 87, 100, 10}};
+		{213, 0, 0, LASTOBJ, RANGEINPUT, (void*)text2, 20, 87, 100, 10}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, j, k, l, ic, n, res, width, height, cType = 200;
+	int i, j, k, l, ic, n, res, cType = 200;
 	bool bRet = false;
 	double x, y;
 	AccRange *rX = 0L, *rY = 0L;
@@ -3793,10 +3807,10 @@ PolarPlot::AddPlot()
 	Function *func;
 	anyOutput *cdisp = Undo.cdisp;
 
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	sprintf(text2, "b1:b%d", height);
+	if(!parent || !data) return false;
+	UseRangeMark(data, 1, text1, text2);
 	if(!(Dlg = new DlgRoot(PolDlg)))return false;
+	Dlg->ItemCmd(211, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(213, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Add Polar Plot", 50, 50, 388, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -4530,48 +4544,59 @@ int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int
 	return res;
 }
 
+static char *StackBar_DlgTmpl =
+		"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,11,100,ISPARENT | CHECKED, SHEET,1,5,10,140,100\n"
+		"11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
+		"12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
+		"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+		"100,101,,,LTEXT,4,15,30,60,8\n"
+		"101,152,,,RANGEINPUT,5,25,40,100,10\n"
+		"152,153,,ISPARENT | CHECKED,GROUPBOX,6, 12, 60, 128, 45\n"
+		"153,154,,,LTEXT,0,25,65,60,8\n"
+		"154,155,,,RANGEINPUT,5,25,75,100,10\n"
+		"155,156,0,,PUSHBUTTON,-8,95,87,30,12\n"
+		"156,,,,PUSHBUTTON,-9,60,87,35,12\n"
+		"200,201,,CHECKED,RADIO1,7,25,35,60,8\n"
+		"201,202,,,RADIO1,8,25,50,60,8\n"
+		"202,203,,,RTEXT,9,31,65,38,8\n"
+		"203,204,,,EDVAL1,10,70,65,30,10\n"
+		"204,,,,CHECKBOX,11,25,90,60,8\n"
+		"300,,,LASTOBJ | NOSELECT, ODBUTTON,12,20,35,80,60";
+
 bool
 StackBar::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 25, 10, "Data"};
 	TabSHEET tab2 = {25, 55, 10, "Details"};
 	TabSHEET tab3 = {55, 90, 10, "Scheme"};
-	DlgInfo StackBarDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
-		{3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
-		{11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
-		{12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
-		{20, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
-		{101, 152, 0, 0x0L, RANGEINPUT, TmpTxt, 25, 40, 100, 10},
-		{152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
-		{153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
-		{154, 155, 0, 0x0L, RANGEINPUT, 0L, 25, 75, 100, 10},
-		{155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
-		{156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
-		{200, 201, 0, CHECKED, RADIO1, (void*)" add each y to start value", 25, 35, 60, 8},
-		{201, 202, 0, 0x0L, RADIO1, (void*)" subtract each y from start value", 25, 50, 60, 8},
-		{202, 203, 0, 0x0L, RTEXT, (void*)"start value:", 31, 65, 38, 8},
-		{203, 204, 0, 0x0L, EDVAL1, &StartVal, 70, 65, 30, 10},
-		{204, 0, 0, 0x0L, CHECKBOX, (void*)" horizontal plot", 25, 90, 60, 8},
-		{300, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 35, 80, 60}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+		(void*)TmpTxt, (void*)" ranges for y values ", (void*)" add each y to start value",
+		(void*)" subtract each y from start value", (void*)"start value:", (void*)&StartVal,
+		(void*)" horizontal plot", (void*)(OD_scheme)};
+	DlgInfo *StackBarDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, sc, j, res, width, height, currYR = 0, maxYR = 0, nx = 0, ny;
+	int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny;
 	bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
-	char **rd;
+	char **rd = 0L;
 	AccRange *rX = 0L, *rY = 0L;
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(TmpTxt, "a1:a%d", height);
-	if(!(rd = (char**)calloc(1, sizeof(char*))))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(!(StackBarDlg = CompileDialog(StackBar_DlgTmpl, dyndata))) return false;
+	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
-	hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked bar plot" : 
-		(char*)"Stacked polygons", 50, 50, 420, 260, Dlg, 0x0L);
+	hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked Bar Plot" : 
+		(char*)"Stacked Polygons", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
 			if(currYR >0) {
@@ -4653,13 +4678,40 @@ StackBar::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
 		free(rd);
 		}
-	if(rX) delete rX;		if(rY) delete rY;
+	if(rX) delete rX;		if(rY) delete rY;		free(StackBarDlg);
 	return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // 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"
+	"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";
+
 bool
 GroupBars::PropertyDlg()
 {
@@ -4667,45 +4719,33 @@ GroupBars::PropertyDlg()
 	TabSHEET tab2 = {25, 55, 10, "Details"};
 	TabSHEET tab3 = {55, 90, 10, "Scheme"};
 	double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
-	DlgInfo GBDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 90},
-		{5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 90},
-		{6, 10, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 90},
-		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"Get values from spreadsheet:", 10, 25, 60, 8},
-		{101, 150, 0, 0x0L, LTEXT, (void*)"All ranges should have equal size!", 10, 33, 60, 8},
-		{150, 0, 153, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 10, 50, 110, 45},
-		{153, 154, 0, 0x0L, LTEXT, 0L, 15, 55, 60, 8},
-		{154, 155, 0, 0x0L, RANGEINPUT, 0L, 15, 65, 100, 10},
-		{155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 85, 77, 30, 12},
-		{156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 50, 77, 35, 12},
-		{200, 201, 0, 0x0L, RTEXT, (void*)"start value", 10, 35, 38, 8},
-		{201, 202, 0, 0x0L, EDVAL1, (void*)&start, 58, 35, 35, 10},
-		{202, 203, 0, 0x0L, RTEXT, (void*)"group step", 10, 50, 38, 8},
-		{203, 204, 0, 0x0L, EDVAL1, (void*)&step, 58, 50, 35, 10},
-		{204, 205, 0, 0x0L, RTEXT, (void*)"bar width", 10, 65, 38, 8},
-		{205, 206, 0, 0x0L, EDVAL1, (void*)&bw, 58, 65, 35, 10},
-		{206, 207, 0, 0x0L, LTEXT, (void*)"%", 95, 65, 8, 8},
-		{207, 208, 0, 0x0L, RTEXT, (void*)"group gap", 10, 80, 38, 8},
-		{208, 209, 0, 0x0L, EDVAL1, (void*)&gg, 58, 80, 35, 10},
-		{209, 0, 0, 0x0L, LTEXT, (void*)"%", 95, 80, 8, 8},
-		{300, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 30, 90, 60}};
+	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)};
+	DlgInfo *GBDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	bool bRet = false, updateYR = true, bContinue = false;
-	char **rd;
+	char **rd = 0L;
 	Bar **bars = 0L;
 	AccRange *rY = 0L;
-	int i, ic, res, ix, iy, ny, sc = 0, currYR = 0, maxYR = 0;
+	int i, j, ic, res, ix, iy, ny, sc = 0, currYR = 0, maxYR = 0;
 	double x, y, xinc;
 
 	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*)))) {
+		for(i=0, j= 0; i <= 1000; i +=100) 
+			if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		}
 	Id = GO_STACKBAR;
-	if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(GBDlg)))return false;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+	else Dlg->SetText(154, "");
 	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Grouped bar chart", 50, 50, 370, 240, Dlg, 0x0L);
 	do {
@@ -4786,7 +4826,7 @@ GroupBars::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
 		free(rd);
 		}
-	if(rY) delete rY;
+	if(rY) delete rY;		free(GBDlg);
 	return bRet;
 }
 
@@ -4812,10 +4852,10 @@ Waterfall::PropertyDlg()
 		{12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
 		{20, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
 		{100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
-		{101, 152, 0, 0x0L, RANGEINPUT, text1, 25, 40, 100, 10},
+		{101, 152, 0, 0x0L, RANGEINPUT, TmpTxt, 25, 40, 100, 10},
 		{152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
 		{153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
-		{154, 155, 0, 0x0L, RANGEINPUT, 0L, 25, 75, 100, 10},
+		{154, 155, 0, 0x0L, RANGEINPUT, TmpTxt, 25, 75, 100, 10},
 		{155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
 		{156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
 		{200, 201, 0, 0x0L, LTEXT, (void*)"line to line displacement:", 20, 35, 80, 8},
@@ -4838,16 +4878,20 @@ Waterfall::PropertyDlg()
 		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, res, width, height, currYR=0, maxYR=0, nx=0, ny;
-	char **rd;
+	int i, j, res, currYR=0, maxYR=0, nx=0, ny;
+	char **rd = 0L;
 	bool updateYR = true, bContinue = false, bRet = false, bUseSch;
 	AccRange *rX = 0L, *rY = 0L;
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	if(!(rd = (char**)calloc(1, sizeof(char*))))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(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create waterfall plot", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
@@ -4922,6 +4966,34 @@ Waterfall::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create a multi data line plot
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *MultiLineDlg_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,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
+	"11,20,300,ISPARENT,SHEET,2,5,10,140,100\n"
+	"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,101,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,75\n"
+	"101,102,,,LTEXT,0,25,39,60,8\n"
+	"102,103,,,RANGEINPUT,-15,25,49,100,10\n"
+	"103,104,,,LTEXT,0,25,61,60,8\n"
+	"104,105,,,RANGEINPUT,-16,25,71,100,10\n"
+	"105,106,,,PUSHBUTTON,-8,95,87,30,12\n"
+	"106,107,,,PUSHBUTTON,-9,60,87,35,12\n"
+	"107,108,,OWNDIALOG,COLBUTT,4,25,87,20,12\n"
+	"108,,,,LTEXT,12,47,90,30,9\n"
+	"300,301,,TOUCHEXIT, RADIO1,13,20,35,80,9\n"
+	"301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
+	"302,303,,CHECKED | TOUCHEXIT, RADIO1,14,20,55,80,9\n"
+	"303,304,,ODEXIT,COLBUTT,4,25,70,10,10\n"
+	"304,305,,ODEXIT,COLBUTT,5,37,70,10,10\n"
+	"305,306,,ODEXIT,COLBUTT,6,49,70,10,10\n"
+	"306,307,,ODEXIT,COLBUTT,7,61,70,10,10\n"
+	"307,308,,ODEXIT,COLBUTT,8,73,70,10,10\n"
+	"308,309,,ODEXIT,COLBUTT,9,85,70,10,10\n"
+	"309,310,,ODEXIT,COLBUTT,10,97,70,10,10\n"
+	"310,,,LASTOBJ | ODEXIT,COLBUTT,11,109,70,10,10\n";
+
 bool
 MultiLines::PropertyDlg()
 {
@@ -4931,50 +5003,35 @@ MultiLines::PropertyDlg()
 		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
 	static DWORD defcol = 0x0L;
 	char x_txt[100], y_txt[100];
-	DlgInfo StackBarDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
-		{3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
-		{11, 20, 300, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
-		{20, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for x- and y- values ", 12, 30, 128, 75},
-		{101, 102, 0, 0x0L, LTEXT, 0L, 25, 39, 60, 8},
-		{102, 103, 0, 0x0L, RANGEINPUT, (void*)x_txt, 25, 49, 100, 10},
-		{103, 104, 0, 0x0L, LTEXT, 0L, 25, 61, 60, 8},
-		{104, 105, 0, 0x0L, RANGEINPUT, (void*)y_txt, 25, 71, 100, 10},
-		{105, 106, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
-		{106, 107, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
-		{107, 108, 0, OWNDIALOG, COLBUTTON, (void*)colarr[0], 25, 87, 20, 12},
-		{108, 0, 0, 0x0L, LTEXT, (void*)"line color", 47, 90, 30, 9},
-		{300, 301, 0, TOUCHEXIT, RADIO1, (void*)" common color for lines:", 20, 35, 80, 9},
-		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 105, 35, 20, 10},
-		{302, 303, 0, CHECKED | TOUCHEXIT, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
-		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
-		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
-		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
-		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
-		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
-		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
-		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
-		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
-		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+	DlgInfo *StackBarDlg;
+	void *dyndata[] = {(void*) &tab1, (void*)&tab2, (void*)" ranges for x- and y- values ",
+		(void*)&colarr[0], (void*)&colarr[1], (void*)&colarr[2], (void*)&colarr[3],
+		(void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6], (void*)&colarr[7],
+		(void*)"line color", (void*)" common color for lines:", (void*)" increment color scheme:",
+		(void*)0x000000ff};
 	DlgRoot *Dlg;
 	void *hDlg;
 	char **rdx=0L, **rdy=0L;
 	DWORD *rdc = 0L, curr_col;
-	int i, width, height, res, currYR=0, maxYR=0, s1, s2;
+	int i, j, res, currYR=0, maxYR=0, s1, s2;
 	bool updateYR = true, bContinue = false, bError, bRet = false;
 	AccRange *rX = 0L, *rY = 0L;
 	DataLine *dl;
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(x_txt, "a1:a%d", height);
-	sprintf(y_txt, "b1:b%d", height);
+	if(!(StackBarDlg = CompileDialog(MultiLineDlg_Tmpl, dyndata)))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(TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*))) 
+		&& (rdy = (char**)calloc(12, sizeof(char*))) && (rdc = (DWORD*)malloc(12*sizeof(DWORD)))) {
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) {
+			rdx[j] = strdup(TmpTxt);		rdc[j] = colarr[j%8];	
+			rdy[j] = strdup(TmpTxt+i);		maxYR = j++;
+			}
+		}
 	if(!(Dlg = new DlgRoot(StackBarDlg))) return false;
 	Dlg->ItemCmd(102, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(104, CMD_SET_DATAOBJ, data);
-	hDlg = CreateDlgWnd("Create multi line plot", 50, 50, 420, 260, Dlg, 0x0L);
+	hDlg = CreateDlgWnd("Create Multi Line Plot", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
 		if(updateYR) {
 			if(currYR >0) {
@@ -5088,7 +5145,14 @@ MultiLines::PropertyDlg()
 		case 303:	case 304:	case 305:	case 306:
 		case 307:	case 308:	case 309:	case 310:
 			Dlg->SetCheck(302, 0L, true);
-			Dlg->GetColor(res, &colarr[res-303]);
+			i = res-303;
+			if(rdx && rdy && i <= maxYR && rdc[i] == colarr[i]) {
+				Dlg->GetColor(res, &colarr[i]);		rdc[i] = colarr[i];
+				Dlg->SetColor(107, rdc[currYR]);
+				}
+			else {
+				Dlg->GetColor(res, &colarr[i]);
+				}
 			res = -1;	break;
 			}
 		}while (res < 0);
@@ -5098,7 +5162,7 @@ MultiLines::PropertyDlg()
 		if(xyPlots=(PlotScatt**)calloc(maxYR, sizeof(PlotScatt*))) for(i = numXY = 0; i < maxYR; i++){
 			if(rdx[i] && rdy[i] && rdx[i][0] && rdy[i][0]) {
 				if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
-					dl->SetColor(COL_DATA_LINE, rdc[i]);
+					dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i]);
 					if(xyPlots[numXY] = new PlotScatt(this, data, 0, 0L, dl)) numXY++;
 					else delete dl;
 					}
@@ -5116,7 +5180,7 @@ MultiLines::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rdy[i]) free(rdy[i]);
 		free(rdy);
 		}
-	if(rdc) free(rdc);
+	free(StackBarDlg);		if(rdc) free(rdc);
 	return bRet;
 }
 
@@ -5599,18 +5663,18 @@ Scatt3D::PropertyDlg()
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
 	Dlg->ItemCmd(105, CMD_SET_DATAOBJ, data);
 	for(i = 0; i < 5; i++) Dlg->SetCheck(201+i, 0L, (c_flags & (1<<i))!=0);
-	if(c_flags == 0x2000) {
+	if(c_flags == 0x2000 || c_flags == 0x4000) {
 		Dlg->ShowItem(5, false);		Dlg->ShowItem(6, false);
 		}
 	else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
-	rX = rY = rZ = 0L;
-	rad = defs.GetSize(SIZE_SYMBOL);
+	rX = rY = rZ = 0L;					rad = defs.GetSize(SIZE_SYMBOL);
 #ifdef _WINDOWS
 	for(i = 61; i <= 62; i++) Dlg->TextSize(i, 12);
 #else
 	for(i = 61; i <= 62; i++) Dlg->TextSize(i, 10);
 #endif
-	hDlg = CreateDlgWnd(c_flags != 0x2000 ? (char*)"Create 3D Plot":(char*)"Create Paravent Plot", 50, 50, 388, 300, Dlg, 0x0L);
+	hDlg = CreateDlgWnd(c_flags == 0x2000 ? (char*)"Create Paravent Plot": 
+	c_flags == 0x4000 ? (char*)"Delauney Surface" : (char*)"Create 3D Plot", 50, 50, 388, 300, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -5625,22 +5689,10 @@ Scatt3D::PropertyDlg()
 		case 4:		case 5:		case 6:		//the tab sheets
 			res = -1;
 			break;
-		case 202:
-			Dlg->SetCheck(204, 0L, false);
-			res = -1;
-			break;
-		case 204:
-			Dlg->SetCheck(202, 0L, false);
-			res = -1;
-			break;
-		case 203:
-			Dlg->SetCheck(205, 0L, false);
-			res = -1;
-			break;
-		case 205:
-			Dlg->SetCheck(203, 0L, false);
-			res = -1;
-			break;
+		case 202:		Dlg->SetCheck(204, 0L, false);		res = -1;		break;
+		case 204:		Dlg->SetCheck(202, 0L, false);		res = -1;		break;
+		case 203:		Dlg->SetCheck(205, 0L, false);		res = -1;		break;
+		case 205:		Dlg->SetCheck(203, 0L, false);		res = -1;		break;
 		case 410:	case 411:	case 412:	//axis templates
 			AxisTempl3D = res-410;
 			res = -1;
@@ -5652,8 +5704,8 @@ Scatt3D::PropertyDlg()
 			if(Dlg->GetText(103, text2) && (rY = new AccRange(text2))) n2 = rY->CountItems();
 			if(Dlg->GetText(105, text3) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
 			if(n1 && n2 && n3){
-				if(c_flags == 0x2000) {
-					//no more but a ribbon
+				if(c_flags == 0x2000 || c_flags == 0x4000) {
+					//no more but a ribbon ore surface
 					}
 				else if(n1 == n2 && n2 == n3) {
 					//o.k., three ranges of equal size have been defined
@@ -5693,6 +5745,10 @@ Scatt3D::PropertyDlg()
 			Bounds.Ymin = 0.0;
 			rib = new Ribbon(this, data, text1, text2, text3);
 			}
+		else if(c_flags == 0x4000){
+			Bounds.Ymin = 0.0;
+			rib = SurfTria(this, data, text1, text2, text3);
+			}
 		do {
 			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && 
 				data->GetValue(n, m, &z)){
@@ -6056,7 +6112,9 @@ static char *AddPlot3Dtmpl =
 		"562,563,,EXRADIO,ODBUTTON,2,62,20,25,25\n"
 		"563,564,,EXRADIO,ODBUTTON,2,87,20,25,25\n"
 		"564,565,,EXRADIO,ODBUTTON,2,112,20,25,25\n"
-		"565,,,LASTOBJ | EXRADIO,ODBUTTON,2,12,45,25,25";
+		"565,566,,EXRADIO,ODBUTTON,2,12,45,25,25\n"
+		"566,567,,EXRADIO,ODBUTTON,2,37,45,25,25\n"
+		"567,,,LASTOBJ | EXRADIO,ODBUTTON,2,62,45,25,25";
 
 bool
 Plot3D::AddPlot(int family)
@@ -6075,7 +6133,8 @@ Plot3D::AddPlot(int family)
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch(res) {
-		case 560:	case 561:	case 562:	case 563:	case 564:	case 565:
+		case 560:	case 561:	case 562:	case 563:	case 564:
+		case 565:	case 566:	case 567:
 			if(res == cSel) res = 1;
 			else {
 				cSel = res;		res = -1;
@@ -6091,6 +6150,8 @@ Plot3D::AddPlot(int family)
 		case 563:		p = new BubblePlot3D(this, data);			break;
 		case 564:		p = new Scatt3D(this, data, 0x2000);		break;
 		case 565:		p = new Func3D(this, data);					break;
+		case 566:		p = new FitFunc3D(this, data);				break;
+		case 567:		p = new Scatt3D(this, data, 0x4000);		break;
 		default:		p = 0L;										break;
 			}
 		if(p && p->PropertyDlg()) {
@@ -6133,7 +6194,7 @@ static char *Base25D_DlgTmpl =
 		"101,152,,,RANGEINPUT,5,25,40,100,10\n"
 		"152,153,,ISPARENT | CHECKED,GROUPBOX,6,12,60,128,45\n"
 		"153,154,,,LTEXT,0,25,65,60,8\n"
-		"154,155,,,RANGEINPUT,0,25,75,100,10\n"
+		"154,155,,,RANGEINPUT,5,25,75,100,10\n"
 		"155,156,,,PUSHBUTTON,-8,95,87,30,12\n"
 		"156,,,,PUSHBUTTON,-9,60,87,35,12\n"
 		"200,201,,,LTEXT,7,20,35,80,8\n"
@@ -6161,10 +6222,9 @@ Chart25D::PropertyDlg()
 	static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
 		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
 	static DWORD defcol = 0x00ffffffL;
-	char text1[100];
 	double start_z = 1.0;
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
-		(void*)text1, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
+		(void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
 		(void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for columns:",
 		(void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
 		(void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
@@ -6172,8 +6232,8 @@ Chart25D::PropertyDlg()
 	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, ic, res, width, height, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
-	char **rd;
+	int i, j, ic, res, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
+	char **rd = 0L;
 	double fx, fy, fz, fsz;
 	bool updateYR = true, bContinue = false, bRet = false, bUseSch;
 	AccRange *rX = 0L, *rY = 0L;
@@ -6186,10 +6246,14 @@ Chart25D::PropertyDlg()
 		//Plots alredy defined: jump to config dialog
 		return false;
 		}
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	if(!(rd = (char**)calloc(1, sizeof(char*))))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(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(Bar3D_Dlg))) return false;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create 3D Bar Chart", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
@@ -6301,10 +6365,9 @@ Ribbon25D::PropertyDlg()
 	static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
 		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
 	static DWORD defcol = 0x00ffffffL;
-	char text1[100];
 	double start_z = 1.0;
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
-		(void*)text1, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
+		(void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
 		(void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for ribbons:",
 		(void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
 		(void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
@@ -6312,8 +6375,8 @@ Ribbon25D::PropertyDlg()
 	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, res, width, height, currYR=0, maxYR=0, nx=0, ny, oax;
-	char **rd;
+	int i, j, res, currYR=0, maxYR=0, nx=0, ny, oax;
+	char **rd = 0L;
 	double fz;
 	bool updateYR = true, bContinue = false, bRet = false, bUseSch;
 	AccRange *rX = 0L, *rY = 0L;
@@ -6325,10 +6388,14 @@ Ribbon25D::PropertyDlg()
 		//Plots alredy defined: jump to config dialog
 		return false;
 		}
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	if(!(rd = (char**)calloc(1, sizeof(char*))))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(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) rd[j++] = strdup(TmpTxt+i); maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
 	if(!(Dlg = new DlgRoot(Bar3D_Dlg)))return false;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(154, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Create 3D Ribbon Chart", 50, 50, 420, 260, Dlg, 0x0L);
 	do {
@@ -6374,7 +6441,7 @@ Ribbon25D::PropertyDlg()
 	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
 		if(rd[maxYR]) maxYR++;					fz = start_z;
 		oax = AxisTempl3D;	AxisTempl3D = 1;	CreateAxes();
-		Dlg->GetText(101, text1);
+		Dlg->GetText(101, TmpTxt+100);
 		if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
 			ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
 			ax->min = start_z-dspm.fz;
@@ -6387,7 +6454,7 @@ Ribbon25D::PropertyDlg()
 			}
 		if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
 			for(i = 0; i < maxYR; i++, fz += dspm.fz) {
-				if(plot = new Ribbon(this, data, fz, dspm.fz, text1, rd[i])){
+				if(plot = new Ribbon(this, data, fz, dspm.fz, TmpTxt+100, rd[i])){
 					if(bUseSch) plot->SetColor(COL_POLYGON, colarr[(i & 0x07)]);
 					else plot->SetColor(COL_POLYGON, defcol);
 					plots[nPlots++] = plot;
@@ -7889,86 +7956,87 @@ 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,0,4,ISPARENT | CHECKED,GROUP, 0, 138,40,55,12\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 | CHECKED,SHEET, 6, 10,37,147,90\n"
-		"103,104,540,TOUCHEXIT | ISPARENT,SHEET, 7, 10,37,147,90\n"
-		"104,0,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, 0L, 0,0,0,0\n"
-		"310,311,,TOUCHEXIT | CHECKED | ISRADIO, 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"
-		"400,,410,HIDDEN | CHECKED | ISPARENT, GROUP, 0L, 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 | CHECKED, 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,,,EXRADIO, ODBUTTON, 31, 75,85,25,25\n"
-		"520,521,,EXRADIO | CHECKED, 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 | CHECKED, 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 | CHECKED, 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,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 45,85,25,25";
+		"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 | CHECKED,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,,TOUCHEXIT | CHECKED | ISRADIO,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"
+		"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 | CHECKED,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,,,EXRADIO, ODBUTTON,31,75,85,25,25\n"
+		"520,521,,EXRADIO | CHECKED,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 | CHECKED,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 | CHECKED,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";
 
 bool
 Graph::PropertyDlg()
@@ -8017,23 +8085,23 @@ Graph::PropertyDlg()
 		case -1:
 			bContinue = false;
 			break;
-		case 101:
+		case 101:	//only y data
 			for(i = 500; i <= 505; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
 			res = -1;
 			break;
-		case 102:
+		case 102:	//xy data
 			for(i = 520; i <= 532; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
 			res = -1;
 			break;
-		case 103:
+		case 103:	//x many y data
 			for(i = 540; i <= 544; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
 			res = -1;
 			break;
-		case 104:
-			for(i = 560; i <= 565; i++) if(Dlg->GetCheck(i))selPlt = i;
+		case 104:	//xyz data
+			for(i = 560; i <= 567; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, false);	Dlg->ShowItem(400, true);
 			res = -1;
 			break;
@@ -8065,7 +8133,7 @@ Graph::PropertyDlg()
 		case 540:	case 541:	case 542:	case 543:
 		case 544:
 		case 560:	case 561:	case 562:	case 563:
-		case 564:	case 565:	case 566:
+		case 564:	case 565:	case 566:	case 567:
 			if(res != selPlt) {
 				selPlt = res;
 				res = -1;
@@ -8146,6 +8214,7 @@ Graph::PropertyDlg()
 				else if(Dlg->GetCheck(564)) p = new Plot3D(this, data, 0x2000);
 				else if(Dlg->GetCheck(565)) p = new Func3D(this, data);
 				else if(Dlg->GetCheck(566)) p = new FitFunc3D(this, data);
+				else if(Dlg->GetCheck(567)) p = new Plot3D(this, data, 0x4000);
 				}
 			if(p && p->PropertyDlg()) {
 				if(!Command(CMD_DROP_PLOT, p, 0L)) DeleteGO(p);
@@ -8163,8 +8232,7 @@ Graph::PropertyDlg()
 			break;
 			}
 		}while(res <0);
-	if(!bRet) parent->Command(CMD_DELOBJ, this, NULL);
-	else Command(CMD_SET_DATAOBJ, (void*)data, 0L);
+	Command(CMD_SET_DATAOBJ, (void*)data, 0L);
 	CloseDlgWnd(hDlg);		delete Dlg;		free(GraphDlg);
 	return bRet;
 }
@@ -8291,7 +8359,6 @@ Graph::Configure()
 			break;
 		case 5:
 			Command(CMD_LEGEND, 0L, 0L);
-			res = -1;
 			break;
 		case 6:
 			Command(CMD_LAYERS, 0L, 0L);
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index b9314ca..c3eb457 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 #include <math.h>
 #include "QT_Spec.h"
+#include "menu.h"
 
 extern tag_Units Units[];
 extern GraphObj *CurrGO;			//Selected Graphic Objects
@@ -49,83 +50,6 @@ QWidget *MainWidget =0L;
 POINT CurrWidgetPos = {0,0};
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Menu item identifiers: synchronize this table with rlplot.rc for
-//    compatibility with windows
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#define CM_OPEN        500
-#define CM_SAVEDATAAS  501
-#define CM_EXIT        502
-#define CM_NEWGRAPH    503
-#define CM_NEWPAGE     504
-#define CM_DELGRAPH    505
-#define CM_ADDPLOT     506
-#define CM_ABOUT       507
-#define CM_ADDROWCOL   508
-#define CM_COPYGRAPH   509
-#define CM_SAVEGRAPHAS 510
-#define CM_REDRAW      511
-#define CM_ZOOM25      512
-#define CM_ZOOM50      513
-#define CM_ZOOM100     514
-#define CM_ZOOM200     515
-#define CM_ZOOM400     516
-#define CM_PRINT       517
-#define CM_EXPORT      518
-#define CM_DELOBJ      519
-#define CM_DEFAULTS    522
-#define CM_COPY        523
-#define CM_PASTE       524
-#define CM_UPDATE      525
-#define CM_ADDAXIS     526
-#define CM_UNDO        527
-#define CM_ZOOMIN      528
-#define CM_ZOOMOUT     529
-#define CM_ZOOMFIT     530
-#define CM_FILE1       531
-#define CM_FILE2       532
-#define CM_FILE3       533
-#define CM_FILE4       534
-#define CM_FILE5       535
-#define CM_FILE6       536
-#define CM_FILLRANGE   537
-#define CM_CUT         538
-#define CM_LEGEND      539
-#define CM_LAYERS      540
-#define CM_INSROW      541
-#define CM_INSCOL      542
-#define CM_DELROW      543
-#define CM_DELCOL      544
-#define CM_SAVEDATA    545
-
-#define CM_T_STANDARD  550
-#define CM_T_DRAW      551
-#define CM_T_POLYLINE  552
-#define CM_T_POLYGON   553
-#define CM_T_RECTANGLE 554
-#define CM_T_ROUNDREC  555
-#define CM_T_ELLIPSE   556
-#define CM_T_ARROW     557
-#define CM_T_TEXT      558
-
-#define CM_DELKEY      600
-#define CM_LEFTARRKEY  601
-#define CM_RIGHTARRKEY 602
-#define CM_UPARRKEY    603
-#define CM_DOWNARRKEY  604
-#define CM_TAB         605
-#define CM_SHTAB       606
-#define CM_PGUP        607
-#define CM_PGDOWN      608
-#define CM_POS_FIRST   609
-#define CM_POS_LAST    610
-#define CM_SHLEFT      611
-#define CM_SHRIGHT     612
-#define CM_SHUP        613
-#define CM_SHDOWN      614
-#define CM_SHPGUP      615
-#define CM_SHPGDOWN    616
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Exute a file open dialog for the different situations
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char UserFileName[600];
@@ -662,7 +586,8 @@ void CopyData(GraphObj *g)
 
 void CopyGraph(GraphObj *g)
 {
-	CopyData(g);
+	if(g->Id == GO_PAGE && CurrGraph) CopyData(CurrGraph);
+	else CopyData(g);
 }
 
 void EmptyClip()
@@ -1503,9 +1428,6 @@ OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
 
 OutputQT::~OutputQT()
 {
-	if(BaseObj) {
-		BaseObj->Command(CMD_CAN_DELETE, 0L, 0L);
-		}
 	if(qPainter.isActive()) qPainter.end();
 	if(widget)	delete widget;	widget = 0L;
 	HideTextCursorObj(this);
@@ -1568,6 +1490,54 @@ unsigned char paste_mask[] = {	//paste cursor mask
 	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
 /*
@@ -1595,9 +1565,9 @@ OutputQT::MouseCursor(int cid, bool force)
 {
 	if(cid == cCursor && !force) return;
 	if(cid == MC_LAST) cid = cCursor;
-	QBitmap cb(16, 16, hand_bits, TRUE);	QBitmap cm(16, 16, hand_mask, TRUE);
-	QBitmap zb(16, 16, zoom_bits, TRUE);	QBitmap zm(16, 16, zoom_mask, TRUE);
-	QBitmap pb(16, 16, paste_bits, TRUE);	QBitmap pm(16, 16, paste_mask, TRUE);
+	QBitmap *bits, *mask;
+	bits = mask = 0L;
+
 	switch(cid) {
 #ifdef Q_CHECK_PTR				//Qt version 3
 	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
@@ -1621,16 +1591,43 @@ OutputQT::MouseCursor(int cid, bool force)
 	case MC_SALL:	widget->setCursor(QCursor(SizeAllCursor));	break;
 #endif
 	case MC_MOVE:
-		widget->setCursor(QCursor(cb, cm, 7, 7));
+		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:
-		widget->setCursor(QCursor(zb, zm, 7, 7));
+		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:
-		widget->setCursor(QCursor(pb, pm, 2, 2));
+		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;
 }
 
@@ -1774,13 +1771,18 @@ OutputQT::SetMenu(int type)
 		graph->insertItem("&Flush Graph(s)", widget, SLOT(cmDelGraph()));
 		graph->insertSeparator();
 		graph->insertItem("&Settings", widget, SLOT(cmDefaults()));
+
+		QPopupMenu *stats = new QPopupMenu(widget);
+		stats->insertItem("&Anova", widget, SLOT(cmRepanov()));
+		stats->insertItem("&Regression", widget, SLOT(cmRepregr()));
 
 		QPopupMenu *about = new QPopupMenu(widget);
 		about->insertItem("&About ...", widget, SLOT(cmAbout()));
 
 		menu = new QMenuBar(widget);
-		menu->insertItem("&File", file);			menu->insertItem("&Edit", edit);
-		menu->insertItem("&Graph", graph);			menu->insertItem("&?", about);
+		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);
@@ -2370,7 +2372,19 @@ void
 RLPwidget::cmtText()
 {
 	ToolMenu(BaseObj, OutputClass, TM_TEXT);
-}
+}
+
+void
+RLPwidget::cmRepanov()
+{
+	if(BaseObj) rep_anova(BaseObj, BaseObj->data);
+}
+
+void
+RLPwidget::cmRepregr()
+{
+	if(BaseObj) rep_regression(BaseObj, BaseObj->data);
+}
 
 //protected: widget events
 void
diff --git a/QT_Spec.h b/QT_Spec.h
index 2340a85..43d6c53 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -172,6 +172,8 @@ public slots:
 	void cmtEllipse();
 	void cmtArrow();
 	void cmtText();
+	void cmRepanov();
+	void cmRepregr();
 	void cmFile1() {openHistoryFile(0);};
 	void cmFile2() {openHistoryFile(1);};
 	void cmFile3() {openHistoryFile(2);};
diff --git a/RLPLOT.RC b/RLPLOT.RC
index 9c502ec..cdf725d 100755
--- a/RLPLOT.RC
+++ b/RLPLOT.RC
@@ -16,78 +16,6 @@
 //    along with RLPlot; if not, write to the Free Software
 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 //
-#define CM_OPEN        500
-#define CM_SAVEDATAAS  501
-#define CM_EXIT        502
-#define CM_NEWGRAPH    503
-#define CM_NEWPAGE     504
-#define CM_DELGRAPH    505
-#define CM_ADDPLOT     506
-#define CM_ABOUT       507
-#define CM_ADDROWCOL   508
-#define CM_COPYGRAPH   509
-#define CM_SAVEGRAPHAS 510
-#define CM_REDRAW      511
-#define CM_ZOOM25      512
-#define CM_ZOOM50      513
-#define CM_ZOOM100     514
-#define CM_ZOOM200     515
-#define CM_ZOOM400     516
-#define CM_PRINT       517
-#define CM_EXPORT      518
-#define CM_DELOBJ      519
-#define CM_DEFAULTS    522
-#define CM_COPY        523
-#define CM_PASTE       524
-#define CM_UPDATE      525
-#define CM_ADDAXIS     526
-#define CM_UNDO        527
-#define CM_ZOOMIN      528
-#define CM_ZOOMOUT     529
-#define CM_ZOOMFIT     530
-#define CM_FILE1       531
-#define CM_FILE2       532
-#define CM_FILE3       533
-#define CM_FILE4       534
-#define CM_FILE5       535
-#define CM_FILE6       536
-#define CM_FILLRANGE   537
-#define CM_CUT         538
-#define CM_LEGEND      539
-#define CM_LAYERS      540
-#define CM_INSROW      541
-#define CM_INSCOL      542
-#define CM_DELROW      543
-#define CM_DELCOL      544
-#define CM_SAVEDATA    545
-
-#define CM_T_STANDARD  550
-#define CM_T_DRAW      551
-#define CM_T_POLYLINE  552
-#define CM_T_POLYGON   553
-#define CM_T_RECTANGLE 554
-#define CM_T_ROUNDREC  555
-#define CM_T_ELLIPSE   556
-#define CM_T_ARROW     557
-#define CM_T_TEXT      558
-
-#define CM_DELKEY      600
-#define CM_LEFTARRKEY  601
-#define CM_RIGHTARRKEY 602
-#define CM_UPARRKEY    603
-#define CM_DOWNARRKEY  604
-#define CM_TAB         605
-#define CM_SHTAB       606
-#define CM_PGUP        607
-#define CM_PGDOWN      608
-#define CM_POS_FIRST   609
-#define CM_POS_LAST    610
-#define CM_SHLEFT      611
-#define CM_SHRIGHT     612
-#define CM_SHUP        613
-#define CM_SHDOWN      614
-#define CM_SHPGUP      615
-#define CM_SHPGDOWN    616
 
 #define MENU_1  400
 #define MENU_2  401
@@ -101,6 +29,7 @@
 #ifndef WORKSHOP_INVOKED
 #include <windows.h>
 #include "Version.h"
+#include "menu.h"
 #endif
 
 MENU_1 MENU DISCARDABLE
@@ -204,6 +133,11 @@ BEGIN
         MENUITEM SEPARATOR
         MENUITEM "&Fill Range",					CM_FILLRANGE
     END
+    POPUP "&Statistics"
+    BEGIN
+    	MENUITEM "&Anova"						CM_REPANOV
+    	MENUITEM "&Regression"					CM_REPREGR
+    END
     POPUP "&Graph"
     BEGIN
         MENUITEM "Create &Graph",               CM_NEWGRAPH
diff --git a/TheDialog.cpp b/TheDialog.cpp
index 5e07427..60dae4e 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -3139,7 +3139,9 @@ LinePat::MBtrack(MouseEvent *mev, anyOutput *o)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Dialog meta compiler
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev."};
+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};
 
 DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 {
@@ -3174,6 +3176,7 @@ DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 						case 62296:			Dlg[i].flags |= NOEDIT;			break;
 						case 231330:		Dlg[i].flags |= LASTOBJ;		break;
 						case 224595:		Dlg[i].flags |= EXRADIO;		break;
+						case 60824:			Dlg[i].flags |= ODEXIT;			break;
 							}
 						free(flags[j]);
 						}
@@ -3238,15 +3241,16 @@ DlgInfo *CompileDialog(char* tmpl, void **ptypes)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Use marked ranges as default for dialog ranges
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
+bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 	char *r4, char *r5, char *r6, char *r7, char *r8, char *r9, char *r10)
 {
 	char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
 	char *mrk, **ra =0L;;
-	int i, ranges=0;
+	int i, j, ranges=0;
 	bool success = false;
 	RECT vrc;
 	AccRange *ar;
+	bool bRet = true;
 
 	if(d && type) {
 		d->ValueRec(&vrc);
@@ -3264,6 +3268,29 @@ void UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 				success = true;
 				}
 			break;
+		case 2:
+			for(i = 0; i < 11; i++) if(dst[i]) *(dst[i]) = 0;
+			if(ranges == 1) {
+				for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) {
+					if(dst[i])sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+					}
+				}
+			else if(ranges > 1) {
+				ar = new AccRange(ra[0]);	j = ar->CountItems();	delete ar;
+				for(i = 1; i < 11 && i < ranges; i++){
+					ar = new AccRange(ra[i]);
+					if(j != ar->CountItems()) {
+						InfoBox("Cannot resolve multiple ranges\nwith different sizes.\n\n"
+							"Please select ranges with equal size!");
+						i = 12;		bRet = false;
+						}
+					delete ar;
+					}
+				if(i < 12) for(i = 0; i < 11 && i < ranges; i++){
+					if(dst[i]) strcpy(dst[i], ra[i]);
+					}
+				}
+			success = true;
 			}
 		}
 	else {
@@ -3276,6 +3303,7 @@ void UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 		for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
 		free(ra);
 		}
+	return bRet;
 }
 
 
@@ -3363,21 +3391,25 @@ DWORD GetNewColor(DWORD oldColor)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Configure 3D shading
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *ConfShade_DlgTmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,95,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,95,25,45,12\n"
+	"3,4,100,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+	"4,5,,OWNDIALOG | TOUCHEXIT,COLBUTT,1,60,10,15,10\n"
+	"5,6,,OWNDIALOG | TOUCHEXIT,COLBUTT,2,60,37,15,10\n"
+	"6,7,,OWNDIALOG | TOUCHEXIT,COLBUTT,1,60,49,15,10\n"
+	"7,8,,,RTEXT,3,25,37,30,9\n"
+	"8,9,,,RTEXT,4,25,49,30,9\n"
+	"9,,,,SHADE3D,5,95,50,22,20\n"
+	"100,101,,TOUCHEXIT,RADIO1,6,10,10,50,9\n"
+	"101,,,TOUCHEXIT | LASTOBJ,RADIO1,7,10,25,60,9";
+
 void ConfShade(FillDEF *oldfill)
 {
 	FillDEF newFill;
-	DlgInfo ShadeDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 95, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 95, 25, 45, 12},
-		{3, 4, 100, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
-		{4, 5, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color, 60, 10, 15, 10},
-		{5, 6, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color2, 60, 37, 15, 10},
-		{6, 7, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color, 60, 49, 15, 10},
-		{7, 8, 0, 0x0L, RTEXT, (void*)"HI-color:", 25, 37, 30, 9},
-		{8, 9, 0, 0x0L, RTEXT, (void*)"LO-color:", 25, 49, 30, 9},
-		{9, 0, 0, 0x0L, SHADE3D, &newFill, 95, 50, 22, 20},
-		{100, 101, 0, TOUCHEXIT, RADIO1, (void*)"fixed color:", 10, 10, 50, 9},
-		{101, 0, 0, TOUCHEXIT | LASTOBJ, RADIO1, (void*)"use light sorce:", 10, 25, 60, 9}};
+	void *dyndata[] = {(void*)&oldfill->color, (void*)&oldfill->color2, (void*)"HI-color:",
+		(void*)"LO-color:", (void*)&newFill, (void*)"fixed color:", (void*)"use light sorce:"};
+	DlgInfo *ShadeDlg = CompileDialog(ConfShade_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res;
@@ -3430,8 +3462,7 @@ void ConfShade(FillDEF *oldfill)
 		if(Dlg->GetCheck(100)) oldfill->type &= ~FILL_LIGHT3D;
 		else oldfill->type |= FILL_LIGHT3D;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;			 free(ShadeDlg);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/TheDialog.h b/TheDialog.h
index d3ac27d..c21e44c 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -58,6 +58,7 @@ enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, COLBUTT, FILLBUTTON, SHADE3D, LINE
 #define LASTOBJ      0x00100000L
 
 #define EXRADIO      TOUCHEXIT|ISRADIO
+#define ODEXIT       OWNDIALOG|TOUCHEXIT
 
 //owner draw button commands
 enum {OD_CREATE, OD_DELETE, OD_DRAWNORMAL, OD_DRAWSELECTED, OD_SELECT, OD_MBTRACK,
@@ -528,7 +529,7 @@ private:
 };
 
 //prototypes TheDialog.cpp
-void UseRangeMark(DataObj *d, int type, char* =0L, char* =0L, char* =0L, char* =0L,
+bool UseRangeMark(DataObj *d, int type, char* =0L, char* =0L, char* =0L, char* =0L,
 	char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L);
 DlgInfo *CompileDialog(char* tmpl, void **ptypes);
 
diff --git a/UtilObj.cpp b/UtilObj.cpp
index 0913bb5..0945652 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -908,7 +908,8 @@ EditText::FindType()
 		Align = TXA_VCENTER | TXA_HRIGHT;
 		type = ET_FORMULA;
 		}
-	else if(isdigit(text[0]) || text[0] == '.' || text[0] == defs.DecPoint[0]) {
+	else if(isdigit(text[0]) || ((text[0] == '-' ) || text[0] == '.' 
+		|| text[0] == defs.DecPoint[0]) && (isdigit(text[1]))) {
 		for(i = c1 = c2 = c3 = c4 = 0; text[i]; i++) {
 			switch(text[i]) {
 			case '.':		c1++;		break;
@@ -945,6 +946,16 @@ EditText::FindType()
 			Align = TXA_VCENTER | TXA_HRIGHT;
 			type = ET_BOOL;
 			}
+		else if(0 == strcmp(text, "inf")) {
+			Value = HUGE_VAL;
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_VALUE;
+			}
+		else if(0 == strcmp(text, "-inf")) {
+			Value = -HUGE_VAL;
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_VALUE;
+			}
 		else {
 			Align = TXA_VCENTER | TXA_HLEFT;
 			type = ET_TEXT;
@@ -2005,7 +2016,7 @@ Default::GetSize(int select)
 	case SIZE_CELLWIDTH:			RetVal = 20.0;				break;
 	case SIZE_CELLTEXT:				RetVal = 4.5*ss_txt;		break;
 	case SIZE_RRECT_RAD:			
-		return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL)/2.0;
+		return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL);
 	default:	return 0.0;
 		}
 	switch(cUnits) {
diff --git a/Utils.cpp b/Utils.cpp
index 9d2b6dd..fa95463 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -294,7 +294,9 @@ void TranslateResult(anyResult *res)
 
 	switch (res->type) {
 	case ET_VALUE:
-		sprintf(tr_text, "%g", res->value);
+		if(res->value == HUGE_VAL) strcpy(tr_text, "inf");
+		else if(res->value == -HUGE_VAL) strcpy(tr_text, "-inf");
+		else sprintf(tr_text, "%g", res->value);
 		res->text = tr_text;				return;
 	case ET_BOOL:
 		sprintf(tr_text, "%s", ((int)res->value) ? "true" : "false"); 
diff --git a/Version.h b/Version.h
index ecd91f5..d899ea7 100755
--- a/Version.h
+++ b/Version.h
@@ -16,4 +16,4 @@
 //    along with RLPlot; if not, write to the Free Software
 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 //
-#define SZ_VERSION  "1.1"
+#define SZ_VERSION  "1.1.2"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index 9e9de14..0eac824 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -23,6 +23,7 @@
 #include "WinSpec.h"
 #include "rlplot.rc"
 #include "TheDialog.h"
+#include "menu.h"
 
 extern int dlgtxtheight;
 
@@ -749,9 +750,6 @@ BitMapWin::BitMapWin(GraphObj *g):anyOutput()
 
 BitMapWin::~BitMapWin()
 {
-	if(go) {
-		go->Command(CMD_CAN_DELETE, 0L, 0L);
-		}
 	Undo.KillDisp(this);
 	if(hgo) delete hgo;
 	if(hFont) DeleteObject(hFont);
@@ -1049,6 +1047,55 @@ unsigned char paste_mask[] =	{	//paste cursor mask
 	0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01,
 	0xfc, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff};
 
+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
+	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
+	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
+	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
+	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
+	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
+	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
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f,
+	0xf8, 0x03, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01,
+	0xf8, 0x03, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff};
+
+
 //display 16x16 cursor data: developers utility
 /*
 void disp_bm(unsigned char *tb)
@@ -1101,6 +1148,22 @@ OutputWin::MouseCursor(int cid, bool force)
 		hc = CreateCursor(hInstance, 2, 2, 16, 16, paste_mask, paste_bits);
 		hoc = SetCursor(hc);
 		break;
+	case MC_DRAWPEN:
+		hc = CreateCursor(hInstance, 0, 0, 16, 16, drawpen_mask, drawpen_bits);
+		hoc = SetCursor(hc);
+		break;
+	case MC_DRAWREC:
+		hc = CreateCursor(hInstance, 2, 2, 16, 16, drect_mask, drect_bits);
+		hoc = SetCursor(hc);
+		break;
+	case MC_DRAWRREC:
+		hc = CreateCursor(hInstance, 2, 2, 16, 16, drrect_mask, drrect_bits);
+		hoc = SetCursor(hc);
+		break;
+	case MC_DRAWELLY:
+		hc = CreateCursor(hInstance, 2, 2, 16, 16, delly_mask, delly_bits);
+		hoc = SetCursor(hc);
+		break;
 	default:	return;
 		}
 	if(hoc) DestroyCursor(hoc);
@@ -2295,6 +2358,12 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_DELCOL:
 			g->Command(CMD_DELCOL, 0L, w);
 			return 0;
+		case CM_REPANOV:
+			if(g->data) rep_anova(g, g->data);
+			return 0;
+		case CM_REPREGR:
+			if(g->data) rep_regression(g, g->data);
+			return 0;
 		default:
 			sprintf(TmpTxt, "Command 0x%x (%d)\nreceived", wParam & 0xffff,
 				wParam & 0xffff);
@@ -2305,7 +2374,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		if(g && g->Command(CMD_CAN_CLOSE, 0L, 0L)) {
 			SetWindowLong(hwnd, 0, 0L);		SetWindowLong(hwnd, GWL_USERDATA, 0L);
 			w->go = 0L;
-			DestroyWindow(hwnd);
+			if(g->parent) g->parent->Command(CMD_DELOBJ, g, w);
+			else DestroyWindow(hwnd);
 			}
 		else if(!g) DestroyWindow(hwnd);
 		return 0;
diff --git a/WinSpec.h b/WinSpec.h
index af66052..50a0c99 100755
--- a/WinSpec.h
+++ b/WinSpec.h
@@ -1,4 +1,4 @@
-//WinSpec.h, Copyright (c) 2000, 2001 R.Lackner
+//WinSpec.h, Copyright (c) 2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
diff --git a/exprlp.cpp b/exprlp.cpp
index 5a291a9..309dbdc 100755
--- a/exprlp.cpp
+++ b/exprlp.cpp
@@ -1,4 +1,4 @@
-//exprlp.cpp, Copyright (c) 2002, 2003, 2004, 2005 R.Lackner
+//exprlp.cpp, Copyright (c) 2002-2006 R.Lackner
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -53,357 +53,6 @@ unsigned char* PasteText()
 	return 0L;
 }
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// STUBS: we do not need dialogs
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool ShowLayers(GraphObj *root)
-{
-	return false;
-}
-
-bool GetBitmapRes(double *res, double *width, double *height, char *header)
-{
-	return false;
-}
-
-bool GetPaper(double *w, double *h)
-{
-	*w = *h = 1.0;
-	return true;
-}
- 
-bool Symbol::PropertyDlg()
-{
-	return false;
-}
-
-bool Bubble::PropertyDlg()
-{
-	return false;
-}
-
-bool Bar::PropertyDlg()
-{
-	return false;
-}
-
-bool DataLine::PropertyDlg()
-{
-	return false;
-}
-
-bool DataPolygon::PropertyDlg()
-{
-	return false;
-}
-
-bool RegLine::PropertyDlg()
-{
-	return false;
-}
-
-bool SDellipse::PropertyDlg()
-{
-	return false;
-}
-
-bool ErrorBar::PropertyDlg()
-{
-	return false;
-}
-
-bool Arrow::PropertyDlg()
-{
-	return false;
-}
-
-bool Box::PropertyDlg()
-{
-	return false;
-}
-
-bool Whisker::PropertyDlg()
-{
-	return false;
-}
-
-bool DropLine::PropertyDlg()
-{
-	return false;
-}
-
-bool Sphere::PropertyDlg()
-{
-	return false;
-}
-
-bool Plane3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Brick::PropertyDlg()
-{
-	return false;
-}
-
-bool DropLine3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Arrow3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Line3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Label::PropertyDlg()
-{
-	return false;
-}
-
-bool segment::PropertyDlg()
-{
-	return false;
-}
-
-bool polyline::PropertyDlg()
-{
-	return false;
-}
-
-bool polygon::PropertyDlg()
-{
-	return false;
-}
-
-bool rectangle::PropertyDlg()
-{
-	return false;
-}
-
-bool PlotScatt::PropertyDlg()
-{
-	return false;
-}
-
-bool xyStat::PropertyDlg()
-{
-	return false;
-}
-
-bool Regression::PropertyDlg()
-{
-	return false;
-}
-
-bool FreqDist::PropertyDlg()
-{
-	return false;
-}
-
-bool BubblePlot::PropertyDlg()
-{
-	return false;
-}
-
-bool PolarPlot::PropertyDlg()
-{
-	return false;
-}
-
-bool PolarPlot::Config()
-{
-	return false;
-}
-
-bool BoxPlot::PropertyDlg()
-{
-	return false;
-}
-
-bool DensDisp::PropertyDlg()
-{
-	return false;
-}
-
-bool StackBar::PropertyDlg()
-{
-	return false;
-}
-
-bool Waterfall::PropertyDlg()
-{
-	return false;
-}
-
-bool MultiLines::PropertyDlg()
-{
-	return false;
-}
-
-bool PieChart::PropertyDlg()
-{
-	return false;
-}
-
-bool StarChart::PropertyDlg()
-{
-	return false;
-}
-
-bool Function::PropertyDlg()
-{
-	return false;
-}
-
-bool Grid3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Grid3D::Configure()
-{
-	return false;
-}
-
-bool Scatt3D::PropertyDlg()
-{
-	return false;
-}
-
-bool FitFunc::PropertyDlg()
-{
-	return false;
-}
-
-bool Plot3D::PropertyDlg()
-{
-	return false;
-}
-
-bool Plot3D::AddPlot(int)
-{
-	return false;
-}
-
-bool Chart25D::PropertyDlg()
-{
-	return false;
-}
-
-bool Ribbon25D::PropertyDlg()
-{
-	return false;
-}
-
-bool Func3D::PropertyDlg()
-{
-	return false;
-}
-
-bool FitFunc3D::PropertyDlg()
-{
-	return false;
-}
-
-bool BubblePlot3D::PropertyDlg()
-{
-	return false;
-}
-
-bool GridLine::PropertyDlg()
-{
-	return false;
-}
-
-bool Tick::PropertyDlg()
-{
-	return false;
-}
-
-bool Axis::PropertyDlg()
-{
-	return false;
-}
-
-bool Graph::AddPlot(int family)
-{
-	return false;
-}
-
-bool Graph::PropertyDlg()
-{
-	return false;
-}
-
-bool Graph::Configure()
-{
-	return false;
-}
-
-bool Graph::AddAxis()
-{
-	return false;
-}
-
-bool Page::Configure()
-{
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// some more STUBS .....
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-char *SaveGraphAsName(char *oldname)
-{
-	return name2;
-}
-
-char *OpenGraphName(char *oldname)
-{
-	return 0L;
-}
-
-void HideTextCursor()
-{
-	return;
-}
-
-void HideTextCursorObj(anyOutput *out)
-{
-	return;
-}
-
-void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
-{
-	return;
-}
-
-anyOutput *NewDispClass(GraphObj *g)
-{
-	return 0L;
-}
-
-bool DelDispClass(anyOutput *w)
-{
-	return false;
-}
-
-anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
-{
-	return 0L;
-}
-
-bool DelBitmapClass(anyOutput *w)
-{
-	return false;
-}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create a root object to handle I/O
diff --git a/menu.h b/menu.h
new file mode 100755
index 0000000..3146703
--- /dev/null
+++ b/menu.h
@@ -0,0 +1,97 @@
+//menu.h, (C) 2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or
+//    (at your option) any later version.
+//
+//    RLPlot is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// menu declarations
+//
+
+#define CM_OPEN        500
+#define CM_SAVEDATAAS  501
+#define CM_EXIT        502
+#define CM_NEWGRAPH    503
+#define CM_NEWPAGE     504
+#define CM_DELGRAPH    505
+#define CM_ADDPLOT     506
+#define CM_ABOUT       507
+#define CM_ADDROWCOL   508
+#define CM_COPYGRAPH   509
+#define CM_SAVEGRAPHAS 510
+#define CM_REDRAW      511
+#define CM_ZOOM25      512
+#define CM_ZOOM50      513
+#define CM_ZOOM100     514
+#define CM_ZOOM200     515
+#define CM_ZOOM400     516
+#define CM_PRINT       517
+#define CM_EXPORT      518
+#define CM_DELOBJ      519
+#define CM_DEFAULTS    522
+#define CM_COPY        523
+#define CM_PASTE       524
+#define CM_UPDATE      525
+#define CM_ADDAXIS     526
+#define CM_UNDO        527
+#define CM_ZOOMIN      528
+#define CM_ZOOMOUT     529
+#define CM_ZOOMFIT     530
+#define CM_FILE1       531
+#define CM_FILE2       532
+#define CM_FILE3       533
+#define CM_FILE4       534
+#define CM_FILE5       535
+#define CM_FILE6       536
+#define CM_FILLRANGE   537
+#define CM_CUT         538
+#define CM_LEGEND      539
+#define CM_LAYERS      540
+#define CM_INSROW      541
+#define CM_INSCOL      542
+#define CM_DELROW      543
+#define CM_DELCOL      544
+#define CM_SAVEDATA    545
+
+#define CM_T_STANDARD  550
+#define CM_T_DRAW      551
+#define CM_T_POLYLINE  552
+#define CM_T_POLYGON   553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC  555
+#define CM_T_ELLIPSE   556
+#define CM_T_ARROW     557
+#define CM_T_TEXT      558
+
+#define CM_DELKEY      600
+#define CM_LEFTARRKEY  601
+#define CM_RIGHTARRKEY 602
+#define CM_UPARRKEY    603
+#define CM_DOWNARRKEY  604
+#define CM_TAB         605
+#define CM_SHTAB       606
+#define CM_PGUP        607
+#define CM_PGDOWN      608
+#define CM_POS_FIRST   609
+#define CM_POS_LAST    610
+#define CM_SHLEFT      611
+#define CM_SHRIGHT     612
+#define CM_SHUP        613
+#define CM_SHDOWN      614
+#define CM_SHPGUP      615
+#define CM_SHPGDOWN    616
+
+#define CM_REPANOV     650
+#define CM_REPREGR     651
+
diff --git a/mfcalc.cpp b/mfcalc.cpp
old mode 100755
new mode 100644
index 2e3360c..3705bb6
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -54,7 +54,7 @@
 
 
 /*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005, 2006 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2006 R.Lackner
  parse string and simple math: based on the bison 'mfcalc' example
 
     This file is part of RLPlot.
@@ -270,14 +270,14 @@ static const short yyrhs[] = {    -1,
 static const short yyrline[] = { 0,
    128,   129,   132,   132,   132,   133,   134,   135,   136,   137,
    138,   141,   143,   144,   145,   146,   147,   148,   149,   150,
-   153,   155,   158,   159,   160,   161,   162,   163,   167,   168,
-   169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
-   181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
-   191,   192,   193,   195,   198,   199,   200,   201,   202,   203,
-   204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
-   214,   215,   216,   217,   218,   222,   226,   227,   229,   230,
-   231,   232,   233,   234,   235,   236,   238,   240,   242,   243,
-   244,   245,   246,   247,   248,   249
+   153,   155,   159,   160,   161,   162,   163,   164,   168,   169,
+   170,   171,   172,   173,   174,   175,   176,   177,   178,   179,
+   182,   183,   184,   185,   186,   187,   188,   189,   190,   191,
+   192,   193,   194,   196,   199,   200,   201,   202,   203,   204,
+   205,   206,   207,   208,   209,   210,   211,   212,   213,   214,
+   215,   216,   217,   218,   219,   223,   227,   228,   230,   231,
+   232,   233,   234,   235,   236,   237,   239,   241,   243,   244,
+   245,   246,   247,   248,   249,   250
 };
 #endif
 
@@ -1197,7 +1197,8 @@ case 21:
 {;;
     break;}
 case 22:
-{if(yyval.text = PushString((char*)malloc(strlen(yyvsp[-2].tptr->name) +strlen(yyvsp[0].tptr->name) + 2))) sprintf(yyval.text, "%s:%s", yyvsp[-2].tptr->name, yyvsp[0].tptr->name);;
+{if(yyval.text = PushString("                                            ")) 
+					sprintf(yyval.text, "%s:%s", yyvsp[-2].tptr->name, yyvsp[0].tptr->name); yyval.type = STR;;
     break;}
 case 24:
 {if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
@@ -2275,6 +2276,39 @@ static double normfreq(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double expdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
+static double expinv(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+        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).");
+	return sr->val;
+}
+
+static double expfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
 static double lognormdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -2286,6 +2320,17 @@ static double lognormdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double lognormfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
 static double lognorminv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -2816,16 +2861,16 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
 	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tinv", tinv),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
-	INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
+	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
 	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, "norminv", norminv),
-	INIT_SYM(AFNCT, "normfreq", normfreq),
-	INIT_SYM(AFNCT, "lognormdist", lognormdist),
+	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
+	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
 	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
@@ -3209,6 +3254,10 @@ static int yylex (void)
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
 		h2_nam = Hash2((unsigned char*)tmp_txt);
+		if(h_nam == 1550 && h2_nam == 18852086) {	//'inf' = huge value
+			yylval.val = HUGE_VAL;
+			return yylval.type = NUM;
+			}
 		if(tok = is_ttoken(h_nam, h2_nam)) return tok;
 		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
 			s = putsym(h_nam, h2_nam, VAR);
@@ -3748,3 +3797,11 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
+
+
+
+
+
+
+
+
diff --git a/mfcalc.y b/mfcalc.y
index eb6fb73..3069b87 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -1,6 +1,6 @@
 %{
 /*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005, 2006 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2006 R.Lackner
  parse string and simple math: based on the bison 'mfcalc' example
 
     This file is part of RLPlot.
@@ -152,7 +152,8 @@ str_exp:
 
 range:
 	str_exp			{;}
-	|VAR COLR VAR		{if(yyval.text = PushString((char*)malloc(strlen($1->name) +strlen($3->name) + 2))) sprintf(yyval.text, "%s:%s", $1->name, $3->name);}
+	|VAR COLR VAR		{if(yyval.text = PushString("                                            ")) 
+					sprintf(yyval.text, "%s:%s", $1->name, $3->name); yyval.type = STR;}
 ;
 
 arr:	ARR
@@ -872,6 +873,39 @@ static double normfreq(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double expdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
+static double expinv(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+        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).");
+	return sr->val;
+}
+
+static double expfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
 static double lognormdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -883,6 +917,17 @@ static double lognormdist(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double lognormfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	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).");
+	return sr->val;
+}
+
 static double lognorminv(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
@@ -1413,16 +1458,16 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
 	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tinv", tinv),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
-	INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
+	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
 	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, "norminv", norminv),
-	INIT_SYM(AFNCT, "normfreq", normfreq),
-	INIT_SYM(AFNCT, "lognormdist", lognormdist),
+	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
+	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
 	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
@@ -1806,6 +1851,10 @@ static int yylex (void)
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
 		h2_nam = Hash2((unsigned char*)tmp_txt);
+		if(h_nam == 1550 && h2_nam == 18852086) {	//'inf' = huge value
+			yylval.val = HUGE_VAL;
+			return yylval.type = NUM;
+			}
 		if(tok = is_ttoken(h_nam, h2_nam)) return tok;
 		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
 			s = putsym(h_nam, h2_nam, VAR);
@@ -2345,3 +2394,11 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
+
+
+
+
+
+
+
+
diff --git a/no_gui.cpp b/no_gui.cpp
new file mode 100755
index 0000000..5199654
--- /dev/null
+++ b/no_gui.cpp
@@ -0,0 +1,550 @@
+//no_gui.cpp, Copyright 2000-2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or
+//    (at your option) any later version.
+//
+//    RLPlot is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This modules contains code for builds with no graphical user interface.
+// Builds using the GUI are compiled with use_gui.cpp instead.
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+#include "rlplot.h"
+
+extern char *name1, *name2;				//the filenames
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// STUBS: we do not need this objects or functions without GUI
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
+{
+}
+
+dragHandle::~dragHandle()
+{
+}
+
+void
+dragHandle::DoPlot(anyOutput *o)
+{
+}
+
+bool
+dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	return false;
+}
+
+void *
+dragHandle::ObjThere(int x, int y)
+{
+	return 0L;
+}
+
+void
+dragHandle::Track(POINT *p, anyOutput *o)
+{
+}
+
+dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
+{
+}
+
+dragRect::~dragRect()
+{
+}
+
+void
+dragRect::DoPlot(anyOutput *o)
+{
+}
+
+void *
+dragRect::ObjThere(int x, int y)
+{
+	return 0L;
+}
+
+bool
+dragRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	return false;
+}
+
+Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
+{
+}
+
+Drag3D::~Drag3D()
+{
+}
+
+void *
+Drag3D::ObjThere(int x, int y)
+{
+	return 0L;
+}
+
+void
+Drag3D::DoPlot(anyOutput *o)
+{
+}
+
+FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
+{
+	Id = Id;
+}
+
+FrmRect::~FrmRect()
+{
+}
+
+double
+FrmRect::GetSize(int select)
+{
+	return 0.0;
+}
+
+bool
+FrmRect::SetSize(int select, double value)
+{
+	return false;
+}
+
+bool
+FrmRect::SetColor(int select, DWORD col)
+{
+	return false;
+}
+
+void 
+FrmRect::DoMark(anyOutput *o, bool mark)
+{
+}
+
+void
+FrmRect::DoPlot(anyOutput *o)
+{
+}
+
+bool
+FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	return false;
+}
+
+void *
+FrmRect::ObjThere(int x, int y)
+{
+	return 0L;
+}
+
+void
+FrmRect::Track(POINT *p, anyOutput *o)
+{
+}
+
+bool ShowLayers(GraphObj *root)
+{
+	return false;
+}
+
+bool GetBitmapRes(double *res, double *width, double *height, char *header)
+{
+	return false;
+}
+
+bool GetPaper(double *w, double *h)
+{
+	*w = *h = 1.0;
+	return true;
+}
+ 
+bool Symbol::PropertyDlg()
+{
+	return false;
+}
+
+bool Bubble::PropertyDlg()
+{
+	return false;
+}
+
+bool Bar::PropertyDlg()
+{
+	return false;
+}
+
+bool DataLine::PropertyDlg()
+{
+	return false;
+}
+
+bool DataPolygon::PropertyDlg()
+{
+	return false;
+}
+
+bool RegLine::PropertyDlg()
+{
+	return false;
+}
+
+bool SDellipse::PropertyDlg()
+{
+	return false;
+}
+
+bool ErrorBar::PropertyDlg()
+{
+	return false;
+}
+
+bool Arrow::PropertyDlg()
+{
+	return false;
+}
+
+void * 
+Arrow::ObjThere(int x, int y)
+{
+	return 0L;
+}
+
+void
+Arrow::Track(POINT *p, anyOutput *o)
+{
+}
+
+bool Box::PropertyDlg()
+{
+	return false;
+}
+
+bool Whisker::PropertyDlg()
+{
+	return false;
+}
+
+bool DropLine::PropertyDlg()
+{
+	return false;
+}
+
+bool Sphere::PropertyDlg()
+{
+	return false;
+}
+
+bool Plane3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Brick::PropertyDlg()
+{
+	return false;
+}
+
+bool DropLine3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Arrow3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Line3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Label::PropertyDlg()
+{
+	return false;
+}
+
+void
+Label::ShowCursor(anyOutput *o)
+{
+}
+
+bool
+Label::AddChar(int ci, anyOutput *o)
+{
+	return true;
+}
+
+void
+Label::CalcCursorPos(int x, int y, anyOutput *o)
+{
+}
+
+bool segment::PropertyDlg()
+{
+	return false;
+}
+
+bool polyline::PropertyDlg()
+{
+	return false;
+}
+
+bool polygon::PropertyDlg()
+{
+	return false;
+}
+
+bool rectangle::PropertyDlg()
+{
+	return false;
+}
+
+bool PlotScatt::PropertyDlg()
+{
+	return false;
+}
+
+bool xyStat::PropertyDlg()
+{
+	return false;
+}
+
+bool Regression::PropertyDlg()
+{
+	return false;
+}
+
+bool FreqDist::PropertyDlg()
+{
+	return false;
+}
+
+bool BubblePlot::PropertyDlg()
+{
+	return false;
+}
+
+bool PolarPlot::PropertyDlg()
+{
+	return false;
+}
+
+bool PolarPlot::Config()
+{
+	return false;
+}
+
+bool BoxPlot::PropertyDlg()
+{
+	return false;
+}
+
+bool DensDisp::PropertyDlg()
+{
+	return false;
+}
+
+bool StackBar::PropertyDlg()
+{
+	return false;
+}
+
+bool Waterfall::PropertyDlg()
+{
+	return false;
+}
+
+bool MultiLines::PropertyDlg()
+{
+	return false;
+}
+
+bool PieChart::PropertyDlg()
+{
+	return false;
+}
+
+bool StarChart::PropertyDlg()
+{
+	return false;
+}
+
+bool Function::PropertyDlg()
+{
+	return false;
+}
+
+bool Grid3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Grid3D::Configure()
+{
+	return false;
+}
+
+bool Scatt3D::PropertyDlg()
+{
+	return false;
+}
+
+bool FitFunc::PropertyDlg()
+{
+	return false;
+}
+
+bool Plot3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Plot3D::AddPlot(int)
+{
+	return false;
+}
+
+bool Chart25D::PropertyDlg()
+{
+	return false;
+}
+
+bool Ribbon25D::PropertyDlg()
+{
+	return false;
+}
+
+bool Func3D::PropertyDlg()
+{
+	return false;
+}
+
+bool FitFunc3D::PropertyDlg()
+{
+	return false;
+}
+
+bool BubblePlot3D::PropertyDlg()
+{
+	return false;
+}
+
+bool GridLine::PropertyDlg()
+{
+	return false;
+}
+
+bool Tick::PropertyDlg()
+{
+	return false;
+}
+
+bool Axis::PropertyDlg()
+{
+	return false;
+}
+
+bool Graph::AddPlot(int family)
+{
+	return false;
+}
+
+bool Graph::PropertyDlg()
+{
+	return false;
+}
+
+bool Graph::Configure()
+{
+	return false;
+}
+
+bool Graph::AddAxis()
+{
+	return false;
+}
+
+bool Graph::ExecTool(MouseEvent *mev)
+{
+	return false;
+}
+
+bool Graph::MoveObj(int cmd, GraphObj *g)
+{
+	return false;
+}
+
+bool Graph::DoZoom(char *z)
+{
+	return false;
+}
+
+bool Page::Configure()
+{
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// some more STUBS .....
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+char *SaveGraphAsName(char *oldname)
+{
+	return name2;
+}
+
+char *OpenGraphName(char *oldname)
+{
+	return 0L;
+}
+
+void HideTextCursor()
+{
+	return;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+	return;
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+	return;
+}
+
+anyOutput *NewDispClass(GraphObj *g)
+{
+	return 0L;
+}
+
+bool DelDispClass(anyOutput *w)
+{
+	return false;
+}
+
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
+{
+	return 0L;
+}
+
+bool DelBitmapClass(anyOutput *w)
+{
+	return false;
+}
+
diff --git a/reports.cpp b/reports.cpp
new file mode 100755
index 0000000..bff14c5
--- /dev/null
+++ b/reports.cpp
@@ -0,0 +1,613 @@
+//reports.cpp, Copyright (c) 2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or
+//    (at your option) any later version.
+//
+//    RLPlot is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Create statistical reports
+//
+
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include "TheDialog.h"
+
+extern char TmpTxt[];
+extern Default defs;
+
+//prototypes: WinSpec.cpp
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
+
+static int curr_id;
+static fRECT dBounds;
+static TextDEF txtdef1, txtdef2;
+static double linsp1, linsp2;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// init report variables
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void rep_init()
+{
+	curr_id = 1;
+	txtdef1.ColTxt = txtdef2.ColTxt = 0x0L;
+	txtdef1.ColBg = txtdef2.ColBg = 0x00ffffffL;
+	txtdef1.fSize = defs.GetSize(SIZE_TEXT);
+	txtdef2.fSize = txtdef1.fSize *1.2;
+	txtdef1.RotBL = txtdef2.RotBL = 0.0;
+	txtdef1.RotCHAR = txtdef2.RotCHAR = 0.0;
+	txtdef1.iSize = txtdef2.iSize = 0;
+	txtdef1.Align = txtdef2.Align = TXA_HLEFT | TXA_VTOP;
+	txtdef1.Mode = txtdef2.Mode = TXM_TRANSPARENT;
+	txtdef1.Style = txtdef2.Style = TXS_NORMAL;
+	txtdef1.Font = txtdef2.Font = FONT_HELVETICA;
+	txtdef1.text = txtdef2.text = 0L;
+#ifdef _WINDOWS
+	linsp1 = txtdef1.fSize*1.2;	linsp2 = txtdef1.fSize*1.5;
+#else
+	linsp1 = txtdef1.fSize*1.5;	linsp2 = txtdef1.fSize*2.0;
+#endif
+
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// utility to add a line to a text buffer
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void add_to_buff(char** dest, int *pos, int *csize, char *txt)
+{
+	int len;
+
+	len = strlen(txt);
+	if((*pos+len+1)>= *csize) {
+		*dest = (char*)realloc(*dest, *csize += 1000);
+		}
+	if(*dest) {
+		*pos += sprintf(*dest+*pos, "%s", txt);
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a text label for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td, char*text)
+{
+	int csize, pos = 0;
+	char *res, line[120];
+
+	if(!(res = (char*)malloc(csize = 1000)))return 0L;
+	sprintf(line, "\n[%d=Label]\nPos= %g %g\n", curr_id++, x, y);
+	add_to_buff(&res, &pos, &csize, line);
+	if(moveable) {
+		sprintf(line, "moveable= 1\n");
+		add_to_buff(&res, &pos, &csize, line);
+		}
+	sprintf(line, "TxtDef= 0x00000000 0x00ffffff %g %g %g %d 1 0 0 \"%s\"\n",
+		td->fSize, td->RotBL, td->RotCHAR, align, text);
+	add_to_buff(&res, &pos, &csize, line);
+	return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create general information on report page
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_header(Page *page, char* desc)
+{
+	time_t ti = time(0L);
+	char *txt_obj, label[80];
+	double rpos;
+
+	if(!page) return;
+	rpos = page->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0;
+	if(txt_obj = mk_label(txtdef1.fSize*5.0, page->GetSize(SIZE_GRECT_TOP)+txtdef2.fSize*6.0,
+		false, TXA_HLEFT, &txtdef2, desc)) {
+		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
+		false, TXA_HRIGHT, &txtdef1, ctime(&ti))) {
+		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+	sprintf(label, "RLPlot %s", SZ_VERSION);
+	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
+		false, TXA_HRIGHT, &txtdef1, label)) {
+		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create horizontal ruler
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_hr(GraphObj *parent, double x1, double x2, double y)
+{
+	int csize, pos = 0;
+	char *res, line[120];
+
+	if(!(res = (char*)malloc(csize = 1000)))return;
+	sprintf(line, "\n[%d=polyline]\nData=(2){ %g %g %g %g}\n", curr_id++, x1, y, x2, y);
+	add_to_buff(&res, &pos, &csize, line);
+	sprintf(line, "Line= %g %g 0x0 0x0\n", txtdef1.fSize/20.0, txtdef1.fSize);
+	add_to_buff(&res, &pos, &csize, line);
+	OpenGraph(parent, 0L, (unsigned char*)res, false);
+	free(res);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create report table for anova ...
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void 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*)"Among groups", type == 2 ? (char*)"Unexplained":(char*)"Within groups", "Total"};
+	char *cfmt[8];
+	int i, j, nl, nc[8];
+	double posc[8];
+	char *txt_obj;
+
+	switch(type) {
+	case 1:	case 2:
+		nl = 3;	nc[0] = 5;	nc[1] = 3;	nc[2] = 2;
+		posc[0] = x + txtdef1.fSize*14.0;		posc[1] = posc[0] + txtdef1.fSize*5.0;
+		posc[2] = posc[1] + txtdef1.fSize*6.0;	posc[3] = posc[2] + txtdef1.fSize*6.0;
+		posc[4] = posc[3] + txtdef1.fSize*6.0;	cfmt[0] = "%.0lf";
+		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;
+		}
+	if(type == 1 || type == 2) {
+		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, rheaders[0])) {
+			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);
+			}
+		for(i = 0; i < 5; i++) {
+			if(txt_obj = mk_label(posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i])) {
+				OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				}
+			if(i) posc[i] += linsp1;
+			}
+		mk_hr(parent, x, posc[4], y + linsp1);
+		y += (txtdef1.fSize *1.5);
+		}
+	for(i = 0; i < nl; i++) {
+		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1])) {
+			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+			free(txt_obj);
+			}
+		for(j = 0; j < nc[i]; j++) {
+			if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001)
+				strcpy(TmpTxt, "< 0.0001");
+			else sprintf(TmpTxt, cfmt[j], dda[i][j]);
+			if(txt_obj = mk_label(posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt)) {
+				OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				}
+			}
+		if(i < (nl-2)) y += linsp1;
+		else {
+			mk_hr(parent, x, posc[4], y + linsp1);
+			y += linsp2;
+			}
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a scatterplot for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n)
+{
+	int i, csize, pos, first;
+	char *res, line[80];
+	double size, linew, tmp;
+
+	if(!(res = (char*)malloc(csize = 1000)))return 0L;
+	if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
+	else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
+	linew = defs.GetSize(SIZE_SYM_LINE);
+	first = curr_id;
+	for(i = pos = 0; i < n && res; i++) {
+		sprintf(line, "\n[%d=Symbol]\nPos= %g %g\n", curr_id++, x ? x[i] : (double)(i+1), y[i]);
+		add_to_buff(&res, &pos, &csize, line);
+		sprintf(line, "Size= %g\n", size);
+		add_to_buff(&res, &pos, &csize, line);
+		sprintf(line, "Line= %g 1 0x0 0x0\nFillCol= 0x00ffffff\n", linew);
+		add_to_buff(&res, &pos, &csize, line);
+		}
+	if(ss && ny) {
+		for(i = 0; i < n && res; i++) {
+			if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+			else tmp = 0.0;
+			sprintf(line, "\n[%d=ErrorBar]\nPos= %g %g\n", curr_id++, x ? x[i] : (double)(i+1), y[i]);
+			add_to_buff(&res, &pos, &csize, line);
+			sprintf(line, "Err= %g\nDesc= \"Std. Dev.\"\n", tmp);
+			add_to_buff(&res, &pos, &csize, line);
+			}
+		for(i = 0; i < n && res; i++) {
+			if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+			else tmp = 0.0;
+			sprintf(line, "\n[%d=Label]\nPos= %g %g\n", curr_id++, x ? x[i]:(double)(i+1), y[i] +tmp);
+			add_to_buff(&res, &pos, &csize, line);
+			sprintf(line, "Dist= 0 %g\nFlags= 0x00000011\n", -txtdef1.fSize/4.0);
+			add_to_buff(&res, &pos, &csize, line);
+			sprintf(line, "TxtDef= 0x00000000 0x00ffffff %g %g %g %d 1 0 0 \"%s%d\"\n",
+				txtdef1.fSize, txtdef1.RotBL, txtdef1.RotCHAR, TXA_HCENTER | TXA_VBOTTOM, 
+				n > 6 ? "" : "n = ", ny[i]);
+			add_to_buff(&res, &pos, &csize, line);
+			}
+		}
+	sprintf(line, "\n[%d=PlotScatt]\n", curr_id++);
+	add_to_buff(&res, &pos, &csize, line);
+	sprintf(line, "Bounds= %g %g %g %g\n", dBounds.Xmin, dBounds.Ymax, dBounds.Xmax, dBounds.Ymin);
+	add_to_buff(&res, &pos, &csize, line);
+	sprintf(line, "Symbols=(%d){", n);		add_to_buff(&res, &pos, &csize, line);
+	for(i = 0; i < n; i++, first++) {
+		sprintf(line, "%s%d", i ? "," : "", first);
+		add_to_buff(&res, &pos, &csize, line);
+		if(i && (i%16) && first < (curr_id-2)) {
+			sprintf(line, "\n   ");			add_to_buff(&res, &pos, &csize, line);
+			}
+		}
+	sprintf(line, "}\n");					add_to_buff(&res, &pos, &csize, line);
+	if(ss && ny) {
+		sprintf(line, "ErrBars=(%d){", n);	add_to_buff(&res, &pos, &csize, line);
+		for(i = 0; i < n; i++, first++) {
+			sprintf(line, "%s%d", i ? "," : "", first);
+			add_to_buff(&res, &pos, &csize, line);
+			if(i && (i%16) && first < (curr_id-2)) {
+				sprintf(line, "\n   ");		add_to_buff(&res, &pos, &csize, line);
+				}
+			}
+		sprintf(line, "}\n");				add_to_buff(&res, &pos, &csize, line);
+		sprintf(line, "Labels=(%d){", n);	add_to_buff(&res, &pos, &csize, line);
+		for(i = 0; i < n; i++, first++) {
+			sprintf(line, "%s%d", i ? "," : "", first);
+			add_to_buff(&res, &pos, &csize, line);
+			if(i && (i%16) && first < (curr_id-2)) {
+				sprintf(line, "\n   ");		add_to_buff(&res, &pos, &csize, line);
+				}
+			}
+		sprintf(line, "}\n");				add_to_buff(&res, &pos, &csize, line);
+		}
+	return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AnovaDlg_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,,CHECKED,RADIO1,3,10,55,60,9\n"
+	"103,,,LASTOBJ,RADIO1,4,10,65,60,9";
+void
+rep_anova(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 45, 10, "Anova Input"};
+	DlgInfo *AnovaDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
+		(void*)"variables arranged in columns", (void*)"    -\"-           -\"-      in rows"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	double **cols = 0L, tmp, *csums=0L, mtot, *css=0L, ssa, ssw, sst;
+	double **res_tab = 0L;
+	int i, j, res, nr, nc, ntot, *ncols = 0L;;
+	bool bContinue = false;
+	AccRange *rD =0L;
+	char *mrk, *txt_obj;
+	RECT rec;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(AnovaDlg = CompileDialog(AnovaDlg_Tmpl, dyndata))) return;
+	if(data->Command(CMD_GETMARK, &mrk, 0L)) {
+		strcpy(TmpTxt, mrk);
+		}
+	else {
+		data->ValueRec(&rec);
+		i = sprintf(TmpTxt,"%s%d", Int2ColLabel(rec.left,false), rec.top + 1);
+		sprintf(TmpTxt+i, ":%s%d", Int2ColLabel(rec.right, false), rec.bottom+1);
+		}
+	if(!(Dlg = new DlgRoot(AnovaDlg)))return;
+	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
+	hDlg = CreateDlgWnd("One 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;
+			}
+		}while (res < 0);
+	if(res == 1 && Dlg->GetText(101, TmpTxt) &&(rD = new AccRange(TmpTxt))
+		&& rD->BoundRec(&rec) && (res_tab = (double**)calloc(3, sizeof(double*)))
+		&& (res_tab[0] = (double*) malloc(5*sizeof(double)))
+		&& (res_tab[1] = (double*) malloc(5*sizeof(double)))
+		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))) {
+		rep_init();
+		if(Dlg->GetCheck(102)) {
+			nr = rec.bottom - rec.top +1;		nc = rec.right - rec.left +1;
+			if((cols = (double**)malloc(nc * sizeof(double*))) && (ncols = (int*)malloc(nc * sizeof(int)))) {
+				for(i = rec.left; i <= rec.right; i++) {
+					ncols[i-rec.left] = 0;	cols[i-rec.left] = (double*)malloc(nr * sizeof(double));
+					if(cols[i-rec.left]) for(j = rec.top; j <= rec.bottom; j++) {
+						if(data->GetValue(j, i, &tmp)) cols[i-rec.left][ncols[i-rec.left]++] = tmp;
+						}
+					}
+				}
+			}
+		else {
+			nr = rec.right - rec.left +1;		nc = rec.bottom - rec.top +1;
+			if((cols = (double**)malloc(nc * sizeof(double*))) && (ncols = (int*)malloc(nc * sizeof(int)))) {
+				for(i = rec.top; i <= rec.bottom; i++) {
+					ncols[i-rec.top] = 0;	cols[i-rec.top] = (double*)malloc(nr * sizeof(double));
+					if(cols[i-rec.top]) for(j = rec.left; j <= rec.right; j++) {
+						if(data->GetValue(j, i, &tmp)) cols[i-rec.top][ncols[i-rec.top]++] = tmp;
+						}
+					}
+				}
+			}
+		if(cols && nr >1 && nc >1 && (csums = (double*)malloc(nc *sizeof(double)))
+			&& (css = (double*)malloc(nc *sizeof(double)))) {
+			dBounds.Ymin = HUGE_VAL;		dBounds.Ymax = -HUGE_VAL;
+			for(i = ntot = 0, mtot = 0.0; i < nc; i++) {
+				for(j = 0, csums[i] = 0.0; j < ncols[i]; j++) {
+					csums[i] += cols[i][j];
+					if(dBounds.Ymin > cols[i][j]) dBounds.Ymin = cols[i][j];
+					if(dBounds.Ymax < cols[i][j]) dBounds.Ymax = cols[i][j];
+					}
+				mtot += csums[i];			ntot += ncols[i];
+				if(ncols[i]) csums[i] /= ((double)ncols[i]);
+				}
+			dBounds.Xmin = 0.0;				dBounds.Xmax = nc;
+			if(ntot) mtot /= ((double)ntot);
+			for(i = 0; i < nc; i++) {
+				for(j = 0, css[i] = 0.0; j < ncols[i]; j++) {
+					tmp = cols[i][j] - csums[i];	css[i] += (tmp*tmp);
+					}
+				}
+			for(i = 0, ssa = ssw = sst = 0.0;  i < nc; i++) {
+				tmp =(csums[i] - mtot);		ssa += (tmp*tmp) * ((double)ncols[i]);
+				ssw += css[i];
+				}
+			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]);
+			page = new Page(parent, data);
+			mk_header(page, "<b>One Way ANOVA</b>");
+			if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc))){
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);								graph->moveable = 0;
+				graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
+				graph->GRect.Ymin += (txtdef1.fSize*10.0);	graph->GRect.Ymax += (txtdef1.fSize*10.0);
+				page->Command(CMD_DROP_GRAPH, graph, 0L);
+				}
+			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);
+			}
+		}
+	if(cols) {
+		for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
+		free(cols);
+		}
+	if(res_tab) {
+		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+		free(res_tab);
+		}
+	if(rD) delete rD;	if(ncols) free(ncols);	if(csums) free(csums);
+	if(css) free(css);	CloseDlgWnd(hDlg);	delete Dlg;	free(AnovaDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// linear regression analysis
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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"
+	"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,70,80,25,10\n"
+	"106,107,,,LTEXT,-10,97,80,60,8\n"
+	"107,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
+
+void
+rep_regression(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 60, 10, "Regression Input"};
+	double ci = 95.0;
+	DlgInfo *RegrDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"range for independent variable (x)",
+		(void*)"range for dependent variable (y)", (void*)"confidence interval:",
+		(void*)&ci, (void*)" include origin"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, n, n1, rx, cx, ry, cy, res, align = 0;
+	bool bContinue = false, bParZ;
+	AccRange *rX = 0L, *rY = 0L;
+	double *x = 0L, *y = 0L, **res_tab = 0L;
+	double sx, sy, dx, dy, sxy, sxx, syy, sdy, df, t, ts, ty;
+	double dres[10], ly[4], regr_sum[5][3];
+	char *txt_obj;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(RegrDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
+	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+	if(!(Dlg = new DlgRoot(RegrDlg)))return;
+	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	hDlg = CreateDlgWnd("Linear Regression", 50, 50, 420, 260, Dlg, 0x0L);
+	do {
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 0:
+			if(bContinue) res = -1;
+			else if(Dlg->GetCheck(10)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+		case 1:
+			Dlg->GetValue(105, &ci);			bParZ = Dlg->GetCheck(107);
+			if(rX) delete rX;	if(rY) delete rY;
+			rX = rY = 0L;
+			if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+			n = rX ? rX->CountItems() : 0;
+			if(!n) {
+				ErrorBox("range not specified\nor not valid.");
+				bContinue = true;
+				res = -1;
+				}
+			if(n && Dlg->GetText(103, TmpTxt) && (rY = new AccRange(TmpTxt))){
+				if(n != rY->CountItems()) {
+					ErrorBox("both ranges must be given\nand must have the same size");
+					bContinue = true;
+					res = -1;
+					}
+				}
+			}
+		}while (res < 0);
+	n1 = n;
+	if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double))) 
+		&& (y = (double*)malloc(n*sizeof(double)))
+		&& (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)))) {
+		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])){
+				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++;
+				}
+			}
+		if(!bParZ) {
+			for(i = 0, 	sx = sy = 0.0; i < n; i++) {
+				sx += x[i];			sy += y[i];
+				}
+			dres[2] = sx /n;		dres[3] = sy/n;
+			}
+		else {
+			dres[2] = sx = dres[3] = sy = 0.0;
+			}
+		sxy = sxx = syy = 0.0;
+		for(i = 0; i < n; i++) {
+			dx = x[i]-dres[2];	dy = y[i]-dres[3];
+			sxx += (dx*dx);		syy += (dy*dy);		sxy += (dx*dy);
+			}
+		dres[0] = sxy / sxx;	dres[1] = dres[3] - dres[0] * dres[2];
+		for(i = 0, sdy = 0.0; i < n; i++) {
+			dy = y[i] - (dres[1] + x[i] *dres[0]);
+			sdy += (dy * dy);
+			}
+		df = bParZ ? (n-1) : (n-2);		sdy = sdy/df;					dres[4] = sqrt(sdy/sxx);
+		dres[5] = sxx/(n-1);			dres[6] = syy/(n-1);			dres[7] = sdy;
+		dres[8] = sxy/sdy*sxy/sxx;		dres[9] = f_dist(dres[8], 1.0, df);
+		t = distinv(t_dist, df, 1.0, (100.0-ci)/100.0, 2.0); 
+		if (n && (graph = new Graph(parent, data, 0L))) {
+			i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n", 
+				dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+			i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"", dres[1], dres[0]);
+			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\"", 
+				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			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\"", 
+				dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+			OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+			ts = t * sqrt(dres[7]*((dBounds.Xmax-dres[2])*(dBounds.Xmax-dres[2])/sxx +1.0/(double)n));
+			ty = dBounds.Xmax * dres[0] +dres[1];
+			ly[0] = ty +ts;		ly[1] = ty -ts;
+			ts = t * sqrt(dres[7]*((dBounds.Xmin-dres[2])*(dBounds.Xmin-dres[2])/sxx +1.0/(double)n));
+			ty = dBounds.Xmin * dres[0] +dres[1];
+			ly[2] = ty +ts;		ly[3] = ty -ts;
+			for(i = 0; i < 4; i++) if(ly[i] > -HUGE_VAL && ly[i] < HUGE_VAL) {
+				if(ly[i] < dBounds.Ymin) dBounds.Ymin = ly[i];
+				if(ly[i] > dBounds.Ymax) dBounds.Ymax = ly[i];
+				}
+			if(txt_obj = mk_scatt(x, y, 0L, 0L, n)){
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				}
+			if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x", dres[1],
+				(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
+			else sprintf(TmpTxt, "y = %g * x", fabs(dres[0]));
+			if(txt_obj = mk_label((graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
+				graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt)) {
+				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+				free(txt_obj);
+				}
+			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*10.0);		graph->GRect.Ymax += (txtdef1.fSize*10.0);
+			mk_header(page, "<b>Linear Regression Analysis</b>");
+			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;
+			res_tab[0][2] = res_tab[0][1];			res_tab[1][2] = res_tab[1][1]/df;
+			res_tab[0][3] = dres[8];				res_tab[0][4] = dres[9];
+			regr_sum[1][0] = res_tab[0][1]/syy;		regr_sum[0][0] = sqrt(regr_sum[1][0]);
+			mk_table(page, graph->GRect.Xmin, graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0,
+				2, res_tab);
+			parent->Command(CMD_DROP_GRAPH, page, 0L);
+			}
+		}
+	CloseDlgWnd(hDlg);
+	delete Dlg;				if(res_tab) {
+		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+		free(res_tab);
+		}
+	if(x) free(x);			if(y) free(y);
+	if(rX) delete rX;		if(rY) delete rY;		free(RegrDlg);
+}
diff --git a/rlp_math.cpp b/rlp_math.cpp
index 9c16f60..e8d2aac 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -583,7 +583,7 @@ double norm_dist(double x, double m, double s)
 	return 0.5 + errf((x - m)/(s * _SQRT2))/2.0;
 }
 
-//normal ditribution
+//normal distribution
 double norm_freq(double x, double m, double s)
 {
 	double ex;
@@ -592,12 +592,46 @@ double norm_freq(double x, double m, double s)
 	return ex/(s*sqrt2pi);
 }
 
+//cumulative exponential distribution
+double exp_dist(double x, double l, double s)
+{
+	if(x >= 0.0 && l > 0.0) return 1.0-exp(-x*l);
+	else return 0.0;
+}
+
+//inverse exponential distribution
+double exp_inv(double p, double l, double s)
+{
+	if(p >= 1.0) return HUGE_VAL;
+	if(l <= 0.0) return 0.0;
+	return -log(1.0-p)/l;
+}
+
+//exponential distribution
+double exp_freq(double x, double l, double s)
+{
+	if(x >= 0.0 && l > 0.0) return l*exp(-x*l);
+	else return fabs(l);
+}
+
 //cumulative lognormal distribution
 double lognorm_dist(double x, double m, double s)
 {
 	return 0.5 + errf((log(x) - m)/(s * _SQRT2))/2.0;
 }
 
+//lognormal distribution
+double lognorm_freq(double x, double m, double s)
+{
+	double tmp;
+
+	if(x > 0.0 && m > 0.0 && s > 0.0) {
+		tmp = (log(x)-m)/s;
+		return exp(-0.5*tmp*tmp)/(x*s*sqrt2pi);
+		}
+	return 0.0;
+}
+
 //chi square distribution
 double chi_dist(double x, double df, double)
 {
@@ -636,34 +670,32 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 	double y1, y2;
 
 	*fn = (sf)(x, df1, df2);
-	y1 = (sf)(x * 0.995, df1, df2);
-	y2 = (sf)(x * 1.005, df1, df2);
-	*df = (y2-y1)*100.0/x;
+	if(sf == norm_dist) *df = norm_freq(x, df1,df2);
+	else {
+		y1 = (sf)(x * 0.995, df1, df2);
+		y2 = (sf)(x * 1.005, df1, df2);
+		*df = (y2-y1)*100.0/x;
+		}
 	*fn = *fn - p;
 }
 
 //distinv does actual bisection and Newton-Raphson root finding
 double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0)
 {
-	int j;
+	int j = 0;
 	double df, dx, dxold, f, fh, fl;
 	double swap, temp, xh, xl, rts; 
-	double x1 = 0.0001, x2 = 10000;
-	char info[80];
+	double x1 = x0/2.0, x2 = x0+x1;
 
-	funcd(x1, &fl, &df, sf, df1, df2, p);
-	funcd(x2, &fh, &df, sf, df1, df2, p);
-	for(j = 0; fl*fh >= 0 && j < 10; j++) {
-		x1 /= 2.0;		x2 *= 2.0;
+	do {
 		funcd(x1, &fl, &df, sf, df1, df2, p);
 		funcd(x2, &fh, &df, sf, df1, df2, p);
-		}
-	if(fl*fh >= 0) {
-		sprintf(info, "Value for inverse distribution\nmust be between %g and %g!", x1, x2);
-		InfoBox(info);
-		return 0.0;
-		}
-	if(fl < 0.0) {
+		if(++j > 200) return 0.0;
+		if(fl*fh < 0.0) break;
+		dx = fabs(x2-x1);
+		x1 = (x1 > dx) ? x1-dx : x1/2.0;			x2 += dx;
+		}while(fl*fh >= 0.0);
+	if(fl <= 0.0) {
 		xl = x1;		xh = x2;
 		}
 	else {
@@ -672,7 +704,7 @@ double distinv(double (*sf)(double, double, double), double df1, double df2, dou
 		}
 	rts = x0;	dxold = fabs(x2-x1);	dx = dxold;
 	funcd(rts, &f, &df, sf, df1, df2, p);
-	for(j = 1; j <= 100; j++) {
+	for(j = 1; j <= 500; j++) {
         if((((rts-xh)*df-f)*((rts-xl)*df-f) >= 0.0) || (fabs(2.0*f) > fabs(dxold * df))) {
 			dxold = dx;		dx = 0.5 * (xh-xl);		rts = xl + dx;
 			if(xl == rts) return rts;
@@ -690,7 +722,7 @@ double distinv(double (*sf)(double, double, double), double df1, double df2, dou
 			xh = rts;	fh = f;
 			}
 		}
-	return 0.0;
+	return rts;
 }
 
 //---------------------------------------------------------------------------
@@ -1538,3 +1570,234 @@ void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h
 	if(doy) *doy = dt.doy;			if(h) *h = dt.hours;
 	if(m) *m = dt.minutes;			if(s) *s = dt.seconds;
 }
+
+//---------------------------------------------------------------------------
+// Use the Delauney triangulation to create a 3D mesh of dispersed data
+//
+class Triangle {
+public:
+	Triangle *next;
+	fPOINT3D pt[4];
+
+	void SetRect();
+	bool TestVertex(double x, double y);
+
+private:
+	double cx, cy, r2;				//circumcircle
+	fRECT rc;						//bounding rectangle
+	lfPOINT ld[3];					//line eqations
+};
+
+class Triangulate {
+public:
+	Triangle *trl;
+
+	Triangulate(Triangle *t_list);
+	bool AddEdge(fPOINT3D *p1, fPOINT3D *p2);
+	bool AddVertex(fPOINT3D *v);
+
+private:
+	typedef struct edge {
+		edge *next;
+		fPOINT3D p1, p2;
+	};
+	edge *edges;
+};
+
+void
+Triangle::SetRect()
+{
+	int i, i2;
+	double dy1, dy2, dx, dy;
+	double m1, m2, mx1, mx2, my1, my2;
+
+	//setup bounding rectangle
+	rc.Xmin = rc.Xmax = pt[0].fx;	rc.Ymin = rc.Ymax = pt[0].fy;
+	for(i = 1; i < 3; i++) {
+		if(pt[i].fx < rc.Xmin) rc.Xmin = pt[i].fx;
+		if(pt[i].fx > rc.Xmax) rc.Xmax = pt[i].fx;
+		if(pt[i].fy < rc.Ymin) rc.Ymin = pt[i].fy;
+		if(pt[i].fy > rc.Ymax) rc.Ymax = pt[i].fy;
+		}
+	//get three line equations in 2D
+	for(i = 0; i < 3; i++) {
+		i2 = (i+1)%3;
+		ld[i].fx = pt[i].fy;
+		if(pt[i].fx != pt[i2].fx) {
+			ld[i].fy = (pt[i2].fy - pt[i].fy) / (pt[i2].fx - pt[i].fx);
+			}
+		else ld[i].fy = HUGE_VAL;
+		}
+	//close polygon
+	pt[3].fx = pt[0].fx;	pt[3].fy = pt[0].fy;	pt[3].fz = pt[0].fz;
+	//circumcricle
+	dy1 = fabs(pt[0].fy - pt[1].fy);			dy2 = fabs(pt[1].fy - pt[2].fy);
+	m1 = (pt[0].fx - pt[1].fx)/(pt[1].fy - pt[0].fy);
+	m2 = (pt[1].fx - pt[2].fx)/(pt[2].fy - pt[1].fy);
+	mx1 = (pt[0].fx + pt[1].fx)/2.0;			my1 = (pt[0].fy + pt[1].fy)/2.0;
+	mx2 = (pt[1].fx + pt[2].fx)/2.0;			my2 = (pt[1].fy + pt[2].fy)/2.0;
+	if(dy1 < 1.0e-16 && dy2 < 1.0e-16) {
+		cy = (pt[0].fy + pt[1].fy + pt[2].fy)/3.0;
+		cx = (pt[0].fx + pt[1].fx + pt[2].fx)/3.0;
+		r2 = 0.0;			return;
+		}
+	else if(dy1 < 1.0e-16) {
+		cx = (pt[0].fx + pt[1].fx)/2.0;			cy = m2 * (cx - mx2) + my2;
+		}
+	else if(dy2 < 1.0e-16) {
+		cx = (pt[2].fx + pt[1].fx)/2.0;			cy = m1 * (cx - mx1) + my1;
+		}
+	else {
+		cx = (m1*mx1-m2*mx2+my2-my1)/(m1-m2);	cy = m1*(cx - mx1) + my1;
+		}
+	dx = pt[1].fx - cx;	dy = pt[1].fy - cy;		r2 = dx * dx + dy * dy;
+}
+
+bool
+Triangle::TestVertex(double x, double y)
+{
+	double dx, dy;
+
+	dx = x-cx;		dx = dx * dx;		dy = y-cy;		dy = dy * dy;
+	return (dx+dy)<r2;
+}
+
+Triangulate::Triangulate(Triangle *t_list)
+{
+	trl = t_list;		edges = 0L;
+}
+
+bool
+Triangulate::AddEdge(fPOINT3D *p1, fPOINT3D *p2)
+{
+	edge *ce, *ne;
+
+	//if edge exists delete both the new and the existing edge
+	for(ce = edges, ne = 0L; (ce); ) {
+		if((ce->p1.fx == p1->fx && ce->p1.fy == p1->fy && ce->p1.fz == p1->fz
+			&& ce->p2.fx == p2->fx && ce->p2.fy == p2->fy && ce->p2.fz == p2->fz)
+			|| (ce->p2.fx == p1->fx && ce->p2.fy == p1->fy && ce->p2.fz == p1->fz
+			&& ce->p1.fx == p2->fx && ce->p1.fy == p2->fy && ce->p1.fz == p2->fz)) {
+			if(ne) ne->next = ce->next;
+			else edges = ce->next;
+			delete ce;					return true;
+			}
+		ne = ce;	ce = ce->next;
+		}
+	//come here for new edge
+	if(ne = new edge()) {
+		ne->p1.fx = p1->fx;		ne->p1.fy = p1->fy;		ne->p1.fz = p1->fz;
+		ne->p2.fx = p2->fx;		ne->p2.fy = p2->fy;		ne->p2.fz = p2->fz;
+		ne->next = edges;		edges = ne;
+		}
+	return false;
+}
+
+bool
+Triangulate::AddVertex(fPOINT3D *v)
+{
+	Triangle *trc, *trn, *tr1;
+	edge *ce, *ae;
+
+	for(trc = trl, trn = 0L, edges = 0L; (trc);) {
+		tr1 = trc->next;
+		//delete triangles whose circumcircle enclose the new vertex
+		if(trc->TestVertex(v->fx, v->fy)) {
+			AddEdge(&trc->pt[0], &trc->pt[1]);		AddEdge(&trc->pt[1], &trc->pt[2]);
+			AddEdge(&trc->pt[0], &trc->pt[2]);
+			if(trn) trn->next = trc->next;
+			else trl = trc->next;
+			if(trl == trc) trl = 0L;	
+			delete trc;
+			}
+		else trn = trc;
+		trc = tr1;
+		}
+	//create new triangles from those edges which where found only once
+	for(ce = edges; (ce); ) {
+		if(trn = new Triangle()) {
+			trn->pt[0].fx = ce->p1.fx;	trn->pt[0].fy = ce->p1.fy;	trn->pt[0].fz = ce->p1.fz;
+			trn->pt[1].fx = ce->p2.fx;	trn->pt[1].fy = ce->p2.fy;	trn->pt[1].fz = ce->p2.fz;
+			trn->pt[2].fx = v->fx;		trn->pt[2].fy = v->fy;		trn->pt[2].fz = v->fz;
+			trn->SetRect();				trn->next = trl;			trl = trn;
+			ae = ce->next;				delete(ce);					ce = ae;
+			}
+		}
+	return true;
+}
+
+Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data)
+{
+	AccRange *rX, *rY, *rZ;
+	int i, j, n, rx, cx, ry, cy, rz, cz;
+	double zMin;
+	fPOINT3D *da;
+	fRECT lim;
+	Triangle *trl, *trn;
+	Triangulate *tria;
+
+	rX = rY = rZ = 0L;				trl = trn  = 0L;
+	if((rX = new AccRange(xr)) && (rY = new AccRange(yr)) && (rZ = new AccRange(zr))
+		&& rX->GetFirst(&cx, &rx) && rY->GetFirst(&cy, &ry) && rZ->GetFirst(&cz, &rz)
+		&& (n = rX->CountItems()) && (da = (fPOINT3D*)malloc(n * sizeof(fPOINT3D)))
+		&& (trl = new Triangle()) && (trn = new Triangle())) {
+		//get minima and maxima
+		for(i = j = 0; i < n; i++) {
+			if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz)) {
+				data->GetValue(rx, cx, &da[j].fx);	data->GetValue(ry, cy, &da[j].fy);
+				data->GetValue(rz, cz, &da[j].fz);	j++;
+				}
+			}
+		if(!j) {
+			free(da); delete rX;	delete rY;	delete rZ;	return trl;
+			}
+		for(i = 0, j = n; i < n; i++) {
+			if(i) {
+				if(da[i].fx < lim.Xmin) lim.Xmin = da[i].fx;	if(da[i].fx > lim.Xmax) lim.Xmax = da[i].fx;
+				if(da[i].fy < lim.Ymin) lim.Ymin = da[i].fy;	if(da[i].fy > lim.Ymax) lim.Ymax = da[i].fy;
+				if(da[i].fz < zMin) zMin = da[i].fz;
+				}
+			else {
+				lim.Xmax = lim.Xmin = da[i].fx;		lim.Ymax = lim.Ymin = da[i].fy;		zMin = da[i].fz;
+				}
+			}
+		//setup two super triangles
+		trl->pt[0].fz = trl->pt[1].fz = trl->pt[2].fz = zMin;
+		trn->pt[0].fz = trn->pt[1].fz = trn->pt[2].fz = zMin;
+		trl->pt[0].fx = trn->pt[0].fx = trl->pt[2].fx = lim.Xmin;
+		trl->pt[0].fy = trn->pt[0].fy = trn->pt[1].fy = lim.Ymin;
+		trl->pt[1].fx = trn->pt[2].fx = trn->pt[1].fx = lim.Xmax;
+		trl->pt[1].fy = trn->pt[2].fy = trl->pt[2].fy = lim.Ymax;
+		trl->SetRect();			trn->SetRect();
+		trl->next = trn;		trn->next = 0L;
+		//do triangulation
+		tria = new Triangulate(trl);
+		for(i = 0; i < n; i++) {
+			tria->AddVertex(&da[i]);
+			}
+		free(da);
+		}
+	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
+	trl = tria->trl;	delete tria;		return trl;
+}
+
+Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *xr, char *yr, char *zr)
+{
+	Triangle *trl, *trc, *trn;
+	int i, j, n, npl;
+	double tmp;
+	Plane3D **planes;
+
+	trl = Triangulate1(xr, zr, yr, data);
+	for(i = 0, trc = trl; trc; i++) trc = trc->next;
+	if((n = i) && (planes = (Plane3D**)malloc(n*sizeof(Plane3D*)))) 
+		for(i = npl = 0, trc = trl; trc && i < n; i++) {
+		for(j = 0; j < 4; j++) {	//swap y and z values;
+			tmp = trc->pt[j].fz;	trc->pt[j].fz = trc->pt[j].fy;	trc->pt[j].fy = tmp;
+			}
+		planes[npl++] = new Plane3D(0L, data, trc->pt, 4);
+		trn = trc->next;	delete trc;		trc = trn;
+		}
+	if(npl) return new Ribbon(parent, data, (GraphObj**)planes, npl);
+	return 0L;
+}
diff --git a/rlplot.cpp b/rlplot.cpp
index 6856d42..6e58fb9 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -29,8 +29,8 @@ extern Default defs;
 GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
 Label *CurrLabel = 0L;
 Graph *CurrGraph = 0L;
-dragHandle *CurrHandle = 0L;
 Axis **CurrAxes = 0L;
+dragHandle *CurrHandle = 0L;
 UndoObj Undo;
 int cGraphs = 0;
 int cPlots = 0;
@@ -41,11 +41,8 @@ int cPages = 0;
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 GraphObj::GraphObj(GraphObj *par, DataObj *d)
 {
-	parent = par;
-	data = d;
-	Id = GO_UNKNOWN;
-	type = moveable = 0;
-	name = 0L;
+	parent = par;	data = d;	Id = GO_UNKNOWN;
+	type = moveable = 0;		name = 0L;
 	rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
 }
 
@@ -53,7 +50,7 @@ GraphObj::~GraphObj()
 {
 	if(name)free(name);
 	name = 0L;
-	if(CurrGO == this) CurrGO = 0L;
+	if(CurrGO == this)	CurrGO = 0L;
 	if(TrackGO == this) TrackGO = 0L;
 }
 
@@ -88,854 +85,6 @@ GraphObj::Track(POINT *p, anyOutput *o)
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Spread sheet buttons used for rows and columns
-ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
-{
-	bLBdown = bSelected = bMarked = false;
-	SetMinMaxRect(&rDims, x, y, x+w, y+h);
-	Line.width = 0.0f;				Line.patlength = 1.0f;
-	Line.color = 0x00000000L;		Line.pattern = 0x00000000L;
-	Fill.type = FILL_NONE;			Fill.color = 0x00e8e8e8L;
-	Fill.scale = 1.0;				Fill.hatch = NULL;
-	TextDef.ColTxt = 0x00000000L;	TextDef.ColBg = 0x00ffffffL;
-	TextDef.fSize = 4.0;			TextDef.RotBL = TextDef.RotCHAR = 0.0;
-	TextDef.iSize = 0;				TextDef.Align = TXA_HLEFT | TXA_VTOP;
-	TextDef.Mode = TXM_TRANSPARENT;	TextDef.Style = TXS_NORMAL;
-	TextDef.Font = FONT_HELVETICA;	TextDef.text = 0L;
-}
-
-ssButton::~ssButton()
-{
-	if(TextDef.text) free(TextDef.text);
-}
-
-void
-ssButton::DoPlot(anyOutput *o)
-{
-	POINT pts[3];
-
-	Line.color = 0x00000000L;
-	if(bSelected) {
-		Fill.color = bMarked ? 0x00ffffe0L : 0x00ffffffL;
-		}
-	else {
-		Fill.color = bMarked ? 0x00ffe0e0L : 0x00e8e8e8L;
-		}
-	o->SetLine(&Line);				o->SetFill(&Fill);
-	if(bLBdown){
-		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-		}
-	else {
-		o->oRectangle(rDims.left, rDims.top, rDims.right-1, rDims.bottom-1);
-		Line.color = 0x00000000L;
-		o->SetLine(&Line);
-		pts[0].x = rDims.left;					pts[0].y = pts[1].y = rDims.bottom-1;
-		pts[1].x = pts[2].x = rDims.right-1;	pts[2].y = rDims.top-1;
-		o->oPolyline(pts, 3);
-		Line.color = 0x00ffffffL;
-		o->SetLine(&Line);
-		pts[0].x = pts[1].x = rDims.left;		pts[0].y = rDims.bottom -3;
-		pts[1].y = pts[2].y = rDims.top;		pts[2].x = rDims.right -2;
-		o->oPolyline(pts, 3);
-		}
-	if(TextDef.text) {
-		o->SetTextSpec(&TextDef);
-#ifdef _WINDOWS
-		o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2-1, TextDef.text, 0);
-#else
-		o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2+1, TextDef.text, 0);
-#endif
-		}
-
-}
-void
-ssButton::DoMark(anyOutput *o, bool mark)
-{
-	bLBdown = mark;
-	DoPlot(o);
-	o->UpdateRect(&rDims, false);
-}
-
-bool
-ssButton::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	char *tmptxt;
-	MouseEvent *mev;
-
-	switch (cmd) {
-	case CMD_GETTEXT:
-		if(TextDef.text && tmpl) {
-			strcpy((char*)tmpl, TextDef.text);
-			return true;
-			}
-		return false;
-	case CMD_SELECT:
-		if(tmpl && *((int*)tmpl)) bSelected = true;
-		else bSelected = false;
-		if(o) {
-			DoPlot(o);
-			o->UpdateRect(&rDims, false);
-			}
-		return true;
-	case CMD_SETSTYLE:
-		if(tmpl && *((int*)tmpl)) bMarked = true;
-		else bMarked = false;
-		if(o) {
-			DoPlot(o);		o->UpdateRect(&rDims, false);
-			}
-		return true;
-	case CMD_SETTEXT:
-		if(TextDef.text) free(TextDef.text);
-		if(tmpl) TextDef.text = strdup((char*)tmpl);
-		else TextDef.text = 0L;
-		return true;
-	case CMD_GETTEXTDEF:
-		if(!tmpl) return false;
-		memcpy(tmpl, &TextDef, sizeof(TextDEF));
-		return true;
-	case CMD_SETTEXTDEF:
-		if(!tmpl)return false;
-		tmptxt = TextDef.text;
-		memcpy(&TextDef, tmpl, sizeof(TextDEF));
-		TextDef.text = tmptxt;
-		return true;
-	case CMD_MOUSE_EVENT:
-		if(!o || !(mev = (MouseEvent *) tmpl)) break;
-		if(IsInRect(&rDims, mev->x, mev->y)) {
-			if(bLBdown) {
-				if(!(mev->StateFlags & 0x01)) {
-					o->HideMark();
-					if(bLBdown) {
-						bLBdown = false; DoPlot(o);
-						}
-					}
-				}
-			else if(mev->StateFlags & 0x01) {
-				o->ShowMark(this, MRK_SSB_DRAW);
-				}
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// drag handles are graphic objects which allow the user to interactively
-//   change the size of an object
-dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
-{
-	type = which;
-	Id = GO_DRAGHANDLE;
-	LineDef.width = LineDef.patlength = 0.0;
-	LineDef.color = LineDef.pattern = 0L;
-	FillDef.type = FILL_NONE;
-	FillDef.color = 0x00ffffffL;
-	FillDef.scale = 1.0;
-	FillDef.hatch = 0L;
-	minRC = maxRC = 0L;
-}
-
-dragHandle::~dragHandle()
-{
-	if(minRC) free(minRC);
-	if(maxRC) free(maxRC);
-	if(CurrHandle == this) CurrHandle = 0L;
-}
-
-void
-dragHandle::DoPlot(anyOutput *o)
-{
-	double fx, fy, dx, dy;
-	int ix, iy, idx;
-	fPOINT3D fp3d, ifp3d;
-	bool is3D = false;
-
-	if(!o || !parent) return;
-	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-	SetMinMaxRect(&drec, o->co2ix(parent->GetSize(SIZE_XPOS)+dx), 
-		o->co2iy(parent->GetSize(SIZE_YPOS)+dy), o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx),
-		o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy));
-	switch(type) {
-	case DH_19:		case DH_12:
-		fx = parent->GetSize(SIZE_XPOS);	fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_99:		case DH_22:
-		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_29:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_39:
-		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_49:
-		fx = parent->GetSize(SIZE_XPOS);
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_59:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_69:
-		fx = parent->GetSize(SIZE_XPOS+1);
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_79:
-		fx = parent->GetSize(SIZE_XPOS);
-		fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_89:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_18:	case DH_28:	case DH_38:	case DH_48:
-	case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		fp3d.fx = parent->GetSize(SIZE_XPOS + type - DH_18);
-		fp3d.fy = parent->GetSize(SIZE_YPOS + type - DH_18);
-		fp3d.fz = parent->GetSize(SIZE_ZPOS + type - DH_18);
-		is3D = true;
-		break;
-	default:
-		if(type >= DH_DATA) {
-			fx = parent->GetSize(SIZE_XPOS + type - DH_DATA);
-			fy = parent->GetSize(SIZE_YPOS + type - DH_DATA);
-			FillDef.color = (this == CurrHandle) ? 0x0L : 0x00ffffffL;
-			}
-		else return;
-		}
-	if(is3D) {
-		o->cvec2ivec(&fp3d, &ifp3d);
-		ix = iround(ifp3d.fx);		iy = iround(ifp3d.fy);
-		}
-	else {
-		ix = o->co2ix(fx+dx);	iy = o->co2iy(fy+dy);
-		}
-	SetMinMaxRect(&rDims, ix-4, iy-4, ix+4, iy+4);
-	memcpy(&upd, &rDims, sizeof(RECT));
-	switch(type) {
-	case DH_12:	case DH_22:	case DH_19:	case DH_29:	case DH_39:
-	case DH_49:	case DH_69:	case DH_79:	case DH_89:	case DH_99:
-		o->SetLine(&LineDef);		o->SetFill(&FillDef);
-		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-		o->UpdateRect(&rDims, false);
-		break;
-	case DH_59:
-		o->SetLine(&LineDef);		o->SetFill(&FillDef);
-		IncrementMinMaxRect(&rDims, 2);
-		o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-		IncrementMinMaxRect(&rDims, 1);
-		o->UpdateRect(&rDims, false);
-		break;
-	default:
-		if(type >= DH_DATA) {
-			idx = (type - DH_DATA);
-			o->SetLine(&LineDef);		o->SetFill(&FillDef);
-			if(parent->Id == GO_BEZIER && (idx %3)) {
-				IncrementMinMaxRect(&rDims, -1);
-				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-				}
-			else if(parent->Id == GO_POLYLINE || parent->Id == GO_BEZIER) {
-				o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-				}
-			else {
-				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-				}
-			o->UpdateRect(&rDims, false);
-			}
-		else {
-			IncrementMinMaxRect(&rDims, -1);
-			o->UpdateRect(&rDims, true);
-			}
-		break;
-		}
-}
-
-bool
-dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	lfPOINT pos;
-	int idx;
-
-	if(!parent) return false;
-	switch (cmd) {
-	case CMD_MOUSECURSOR:
-		if(o) switch(type) {
-		case DH_19:	case DH_99:
-			o->MouseCursor(MC_SE, false);							break;
-		case DH_29:	case DH_89:
-			o->MouseCursor(MC_NORTH, false);						break;
-		case DH_39:	case DH_79:
-			o->MouseCursor(MC_NE, false);							break;
-		case DH_49:	case DH_69:
-			o->MouseCursor(MC_EAST, false);							break;
-		default:
-			if(type >= DH_DATA) o->MouseCursor(MC_SALL, false);
-			else o->MouseCursor(MC_MOVE, false);					break;
-			}
-		return true;
-	case CMD_MINRC:
-		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
-		if(tmpl && minRC) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		return true;
-	case CMD_MAXRC:
-		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
-		if(tmpl && maxRC) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		return true;
-	case CMD_MOVE:
-		idx = type >= DH_DATA ? type - DH_DATA : 0;
-		pos.fx = NiceValue(((lfPOINT*)tmpl)[0].fx);
-		pos.fy = NiceValue(((lfPOINT*)tmpl)[0].fy);
-		if(pos.fx == 0.0 && pos.fy == 0.0) return false;
-		parent->Command(CMD_SAVEPOS, &idx, o);
-		switch(type) {
-		case DH_12:
-			parent->SetSize(SIZE_XPOS, pos.fx + parent->GetSize(SIZE_XPOS));
-			parent->SetSize(SIZE_YPOS, pos.fy + parent->GetSize(SIZE_YPOS));
-			break;
-		case DH_22:
-			parent->SetSize(SIZE_XPOS+1, pos.fx + parent->GetSize(SIZE_XPOS+1));
-			parent->SetSize(SIZE_YPOS+1, pos.fy + parent->GetSize(SIZE_YPOS+1));
-			break;
-		case DH_19: parent->parent->SetSize(SIZE_XPOS, 
-						pos.fx + parent->GetSize(SIZE_XPOS));
-		case DH_29: parent->parent->SetSize(SIZE_YPOS,
-						pos.fy + parent->GetSize(SIZE_YPOS));
-			break;
-		case DH_39: parent->parent->SetSize(SIZE_YPOS,
-						pos.fy + parent->GetSize(SIZE_YPOS));
-		case DH_69: parent->parent->SetSize(SIZE_XPOS+1,
-						pos.fx + parent->GetSize(SIZE_XPOS+1));
-			break;
-		case DH_99: parent->parent->SetSize(SIZE_XPOS+1, 
-						pos.fx + parent->GetSize(SIZE_XPOS+1));
-		case DH_89: parent->parent->SetSize(SIZE_YPOS+1,
-						pos.fy + parent->GetSize(SIZE_YPOS+1));
-			break;
-		case DH_79: parent->parent->SetSize(SIZE_YPOS+1,
-						pos.fy + parent->GetSize(SIZE_YPOS+1));
-		case DH_49:
-			parent->parent->SetSize(SIZE_XPOS, 
-						pos.fx + parent->GetSize(SIZE_XPOS));
-			break;
-		case DH_18:	case DH_28:	case DH_38:	case DH_48:
-		case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		case DH_59:
-			return parent->parent->Command(cmd, tmpl, o);
-		default:
-			if (type >= DH_DATA) {
-				parent->SetSize(SIZE_XPOS + idx, pos.fx + parent->GetSize(SIZE_XPOS + idx));
-				parent->SetSize(SIZE_YPOS + idx, pos.fy + parent->GetSize(SIZE_YPOS + idx));
-				CurrGO = parent;
-				}
-			break;
-			}
-		return parent->Command(CMD_REDRAW, 0L, o);
-		break;
-		}
-	return false;
-}
-
-void *
-dragHandle::ObjThere(int x, int y)
-{
-	if(IsInRect(&rDims, x, y)) return (CurrHandle = this);
-	else return 0L;
-}
-
-
-void
-dragHandle::Track(POINT *p, anyOutput *o)
-{
-	POINT p1, p2, pts[5], bez[256];
-	double dx, dy;
-	int i, first=0, last = 0, idx;
-	long nbez;
-	DWORD color;
-
-	if(!parent || !o) return;
-	Command(CMD_MOUSECURSOR, 0L, o);
-	if(upd.right < upd.left) Swap(upd.right, upd.left);
-	if(upd.bottom < upd.top) Swap(upd.bottom, upd.top);
-	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-	IncrementMinMaxRect(&upd, 2);
-	o->UpdateRect(&upd, false);
-	if(type >= DH_19 && type <= DH_99) memcpy(&upd, &drec, sizeof(RECT));
-	color = parent->GetColor(COL_DATA_LINE);
-	switch(type) {
-	case DH_12:
-	case DH_22:
-		pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS)+dx);
-		pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS)+dy);
-		pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx);
-		pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy);
-		if(type == DH_12) {
-			pts[0].x += p->x;			pts[0].y += p->y;
-			}
-		else if(type == DH_22) {
-			pts[1].x += p->x;			pts[1].y += p->y;
-			}
-		UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
-		UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
-		last = 2;
-		break;
-	case DH_19:
-		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = minRC->left;
-		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
-		else upd.left += p->x;
-	case DH_29:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = minRC->top;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = upd.top +p->y >= maxRC->bottom? maxRC->bottom : maxRC->top;
-		else upd.top += p->y;
-		break;
-	case DH_39:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = minRC->top;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = upd.top+p->y >= maxRC->bottom ? maxRC->bottom : maxRC->top;
-		else upd.top += p->y;
-	case DH_69:
-		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = minRC->right;
-		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
-		else upd.right += p->x;
-		break;
-	case DH_99:
-		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = minRC->right;
-		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
-		else upd.right += p->x;
-	case DH_89:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = minRC->bottom;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
-		else upd.bottom += p->y;
-		break;
-	case DH_79:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = minRC->bottom;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
-		else upd.bottom += p->y;
-	case DH_49:
-		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = minRC->left;
-		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
-		else upd.left += p->x;
-		break;
-	case DH_18:	case DH_28:	case DH_38:	case DH_48:
-	case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		CurrGO = this;
-	case DH_59:
-		parent->parent->Track(p, o);
-		return;
-	default:
-		if(type >= DH_DATA) {
-			idx = type - DH_DATA;
-			pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx)+dx);
-			pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx)+dy);
-			pts[1].x += p->x;				pts[1].y += p->y;
-			if(type > DH_DATA) {
-				pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -1)+dx);
-				pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -1)+dy);
-				}
-			else {
-				pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
-				}
-			pts[3].x = pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
-			pts[3].y = pts[2].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +1)+dy);
-			UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
-			UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
-			UpdateMinMaxRect(&upd, pts[2].x, pts[2].y);
-			if(parent ->Id == GO_BEZIER) {
-				switch(idx % 3) {
-				case 0:
-					o->ShowLine(pts, 3, 0x00c0c0c0L);
-					pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
-					for(nbez = 0, i = 1; i < 4; i++) {
-						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
-						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
-						}
-					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
-					o->ShowLine(bez, nbez, color);
-					if(idx < 3) return;
-					pts[3].x = pts[0].x;		pts[3].y = pts[0].y;
-					for(i = nbez = 0, idx -= 3; i < 3; i++) {
-						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
-						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
-						}
-					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
-					o->ShowLine(bez, nbez, color);
-					return;
-				case 1:		
-					pts[3].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +2)+dx);
-					pts[3].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +2)+dy);
-					last = 2;				break;
-				case 2:	
-					pts[2].x = pts[1].x;	pts[2].y = pts[1].y;
-					pts[1].x = pts[0].x;	pts[1].y = pts[0].y;
-					pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -2)+dx);
-					pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -2)+dy);
-					first = 2;	last = 4;	break;
-					}
-				if(idx %3) {
-					nbez = 0;
-					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
-					o->ShowLine(bez, nbez, color);
-					}
-				color = 0x00c0c0c0L;
-				}
-			else last = 3;
-			if(color == 0x0L || color == 0x00ffffffL) color = 0x00c0c0c0L;
-			}
-		else return;
-		}
-	if(type >= DH_19 && type <= DH_99) {
-		pts[0].x = pts[4].x = pts[3].x = p1.x = upd.left;	
-		pts[0].y = pts[1].y = pts[4].y = p1.y = upd.top;
-		pts[1].x = pts[2].x = p2.x = upd.right;	
-		pts[2].y = pts[3].y = p2.y = upd.bottom;
-		last = 5;
-		if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
-		}
-	o->ShowLine(pts+first, last-first, color);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// the dragRect object uses nine dragHandles to create a user interface
-//   for modification of rectangular shapes
-dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
-{
-	int i;
-
-	type = which;
-	Id = GO_DRAGRECT;
-	if(handles = (dragHandle**)calloc(9, sizeof(dragHandle*)))
-		for(i = 0; i < 9; i++){
-			if(i == 4 && type == 0) handles[i] = new dragHandle(this, DH_19 + i);
-			else if(i != 4) handles[i] = new dragHandle(this, DH_19 + i);
-			}
-}
-
-dragRect::~dragRect()
-{
-	int i;
-
-	if(handles) for(i = 0; i < 9; i++) if(handles[i]) DeleteGO(handles[i]);
-}
-
-void
-dragRect::DoPlot(anyOutput *o)
-{
-	int i;
-
-	if(handles) for(i = 0; i < 9; i++) if(handles[i]) handles[i]->DoPlot(o);
-}
-
-bool
-dragRect::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	int i;
-
-	if(!parent) return false;
-	switch (cmd) {
-	case CMD_MINRC:
-	case CMD_MAXRC:
-		if(handles) for(i = 0; i < 9; i++) {
-			if(handles[i]) handles[i]->Command(cmd, tmpl, o);
-			}
-		break;
-	case CMD_SAVEPOS:
-	case CMD_REDRAW:
-		return parent->Command(cmd, tmpl, o);
-		}
-	return false;
-}
-
-void *
-dragRect::ObjThere(int x, int y)
-{
-	int i;
-	void *go;
-
-	if(handles)	for(i = 0; i < 9; i++) 
-		if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
-	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// implement some kind of virtual trackball for 3D plots
-Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
-{
-	int i;
-
-	Id = GO_DRAG3D;
-	if(handles = (dragHandle**)calloc(8, sizeof(dragHandle*)))
-		for(i = 0; i < 8; i++){
-			handles[i] = new dragHandle(this, DH_18 + i);
-			}
-}
-
-Drag3D::~Drag3D()
-{
-	int i;
-
-	if(handles) for(i = 0; i < 8; i++) if(handles[i]) DeleteGO(handles[i]);
-}
-
-void
-Drag3D::DoPlot(anyOutput *o)
-{
-	int i;
-
-	if(handles) for(i = 0; i < 8; i++) if(handles[i]) handles[i]->DoPlot(o);
-}
-
-void *
-Drag3D::ObjThere(int x, int y)
-{
-	int i;
-	void *go;
-
-	if(handles)	for(i = 0; i < 8; i++) 
-		if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
-	return 0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// frame rectangle
-FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
-{
-	parent = par;
-	limRC = lim;	cRC = c;	chldRC = chld;
-	drag = 0L;		mo = 0L;
-	Id = GO_FRAMERECT;
-	moveable = true;
-	Fill.type = FILL_NONE;
-	Line.color = FillLine.color = Fill.color = 0x00ffffffL;
-	Line.width = FillLine.width = 0.0;
-	Line.patlength = FillLine.patlength = Fill.scale = 1.0;
-	Line.pattern = FillLine.pattern = 0x0L;
-	Fill.hatch = &FillLine;
-	minRC = maxRC = 0L;
-}
-
-FrmRect::~FrmRect()
-{
-	if(drag) DeleteGO(drag);		drag = 0L;
-	if(minRC) free(minRC);			minRC = 0L;	
-	if(maxRC) free(maxRC);			maxRC = 0L;
-	if(mo) DelBitmapClass(mo);		mo = 0L;
-}
-
-double
-FrmRect::GetSize(int select)
-{
-	switch(select) {
-	case SIZE_XPOS:		return CurrRect.Xmin;
-	case SIZE_XPOS+1:	return CurrRect.Xmax;
-	case SIZE_YPOS:		return CurrRect.Ymin;
-	case SIZE_YPOS+1:	return CurrRect.Ymax;
-		}
-	return 0.0;
-}
-
-bool
-FrmRect::SetSize(int select, double value)
-{
-	double tmp, o_left, o_top;
-
-	o_left = cRC->Xmin;		o_top = cRC->Ymin;
-	switch (select & 0xfff) {
-	case SIZE_XPOS:
-		if(limRC) value -= limRC->Xmin;
-		if(swapX) cRC->Xmax = value;
-		else cRC->Xmin = value;
-		break;
-	case SIZE_XPOS+1:
-		if(limRC) value -= limRC->Xmin;
-		if(swapX) cRC->Xmin = value;
-		else cRC->Xmax = value;
-		break;
-	case SIZE_YPOS:
-		if(limRC) value -= limRC->Ymin;
-		if(swapY) cRC->Ymin = value;
-		else cRC->Ymax = value;
-		break;
-	case SIZE_YPOS+1:
-		if(limRC) value -= limRC->Ymin;
-		if(swapY) cRC->Ymax = value;
-		else cRC->Ymin = value;
-		break;
-	default: return false;
-		}
-	if((swapX && cRC->Xmin < cRC->Xmax) || (!swapX && cRC->Xmin > cRC->Xmax)) {
-		tmp = cRC->Xmin;	cRC->Xmin = cRC->Xmax;	cRC->Xmax = tmp;
-		}
-	if((swapY && cRC->Ymin > cRC->Ymax) || (!swapY && cRC->Ymin < cRC->Ymax)) {
-		tmp = cRC->Ymin;	cRC->Ymin = cRC->Ymax;	cRC->Ymax = tmp;
-		}
-	if(chldRC) {		//check if new rectangle is not inside child rectangle
-		if(cRC->Xmin > o_left+ chldRC->Xmin) cRC->Xmin = o_left + chldRC->Xmin;
-		if(cRC->Xmax < o_left+ chldRC->Xmax) cRC->Xmax = o_left + chldRC->Xmax;
-		if(cRC->Ymin > o_top+ chldRC->Ymin) cRC->Ymin = o_top + chldRC->Ymin;
-		if(cRC->Ymax < o_top+ chldRC->Ymax) cRC->Ymax = o_top + chldRC->Ymax;
-		}
-	if(chldRC && (o_left != cRC->Xmin || o_top != cRC->Ymin)) {
-		chldRC->Xmin -= (tmp = cRC->Xmin - o_left);		chldRC->Xmax -= tmp;
-		chldRC->Ymin -= (tmp = cRC->Ymin - o_top);		chldRC->Ymax -= tmp;
-		}
-	return true;
-}
-
-bool
-FrmRect::SetColor(int select, DWORD col)
-{
-	switch(select & 0xfff){
-	case COL_DRECT:
-		Line.color = col;
-	case COL_BG:
-		Fill.color = col;		return true;
-	case COL_GRECT:
-		Fill.color = col;		return true;
-	case COL_GRECTLINE:
-		Line.color = col;		return true;
-		}
-	return false;
-}
-
-void 
-FrmRect::DoMark(anyOutput *o, bool mark)
-{
-	if(!parent || !o) return;
-	if(!drag && (drag = new dragRect(this, (!limRC && parent->moveable) ? 0 : 1))){
-		if(minRC) drag->Command(CMD_MINRC, minRC, o);
-		if(maxRC) drag->Command(CMD_MAXRC, maxRC, o);
-		}
-	if(mark && drag){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6);
-		mo = GetRectBitmap(&mrc, o);
-		drag->DoPlot(o);
-		o->UpdateRect(&mrc, false);
-		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-void
-FrmRect::DoPlot(anyOutput *o)
-{
-	int x1, y1, x2, y2;
-	double tmp;
-
-	if(!(cRC) || !o) return;
-	o->dFillCol = Fill.color ^ 0x00ffffff;	//force new brush
-	o->dLineCol = Line.color ^ 0x00ffffff;	//force new pen
-	o->SetLine(&Line);						o->SetFill(&Fill);
-	CurrRect.Xmin = cRC->Xmin;				CurrRect.Xmax = cRC->Xmax;
-	CurrRect.Ymin = cRC->Ymax;				CurrRect.Ymax = cRC->Ymin;
-	if(limRC) {
-		CurrRect.Xmin += limRC->Xmin;		CurrRect.Xmax += limRC->Xmin;
-		CurrRect.Ymin += limRC->Ymin;		CurrRect.Ymax += limRC->Ymin;
-		}
-	if(swapX = (CurrRect.Xmin > CurrRect.Xmax)) {
-		tmp = CurrRect.Xmin;	CurrRect.Xmin = CurrRect.Xmax;	CurrRect.Xmax = tmp;
-		}
-	if(swapY = (CurrRect.Ymin > CurrRect.Ymax)) {
-		tmp = CurrRect.Ymin;	CurrRect.Ymin = CurrRect.Ymax;	CurrRect.Ymax = tmp;
-		}
-	o->oRectangle(x1 = o->co2ix(CurrRect.Xmin), y1 = o->co2iy(CurrRect.Ymin), 
-		x2 = o->co2ix(CurrRect.Xmax), y2 = o->co2iy(CurrRect.Ymax));
-	SetMinMaxRect(&rDims, x1, y1, x2, y2);
-}
-
-bool
-FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	MouseEvent *mev;
-
-	if(!parent) return false;
-	switch (cmd) {
-	case CMD_MOUSE_EVENT:
-		mev = (MouseEvent *) tmpl;
-		switch (mev->Action) {
-		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;
-				return true;
-				}
-			}
-		return false;
-	case CMD_MINRC:
-		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
-		if(minRC && tmpl) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		if(drag) drag->Command(cmd, tmpl, o);
-		return true;
-	case CMD_MAXRC:
-		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
-		if(maxRC && tmpl) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		if(drag) drag->Command(cmd, tmpl, o);
-		return true;
-	case CMD_MOVE:
-		cRC->Xmin += NiceValue(((lfPOINT*)tmpl)[0].fx);
-		cRC->Ymin += NiceValue(((lfPOINT*)tmpl)[0].fy);
-		cRC->Xmax += NiceValue(((lfPOINT*)tmpl)[0].fx);
-		cRC->Ymax += NiceValue(((lfPOINT*)tmpl)[0].fy);
-	case CMD_REDRAW:
-		return parent->Command(CMD_REDRAW, 0L, o);
-	case CMD_SAVEPOS:
-		return parent->Command(cmd, tmpl, o);
-	case CMD_SETCHILD:
-		chldRC = (fRECT*)tmpl;
-		return true;
-		}
-	return false;
-}
-
-void *
-FrmRect::ObjThere(int x, int y)
-{
-	if(drag) return drag->ObjThere(x, y);
-	return 0L;
-}
-
-void
-FrmRect::Track(POINT *p, anyOutput *o)
-{
-	POINT tpts[5];
-	RECT old_rc;
-
-	if(o){
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		o->UpdateRect(&rDims, false);
-		tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(cRC->Xmin)+p->x;		
-		tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(cRC->Ymin)+p->y;
-		tpts[1].y = tpts[2].y = o->co2iy(cRC->Ymax)+p->y;
-		tpts[2].x = tpts[3].x = o->co2ix(cRC->Xmax)+p->x;
-		UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
-		UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);	
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		o->ShowLine(tpts, 5, Fill.color ^ 0x00ffffffL);
-		}
-
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // This is a special object to read certain svg-settings from a *.rlp file
 svgOptions::svgOptions(int src):GraphObj(0L, 0L)
 {
@@ -2119,6 +1268,11 @@ DataLine::LineData(lfPOINT *val, long nval)
 }
 
 void
+DataLine::DrawCurve(anyOutput *target)
+{
+}
+
+void
 DataLine::DrawSpline(anyOutput *target)
 {
 	int i, j, k, klo, khi, ptsize = 1000;
@@ -3166,55 +2320,6 @@ Arrow::Command(int cmd, void *tmpl, anyOutput *o)
 	return false;
 }
 
-void * 
-Arrow::ObjThere(int x, int y)
-{
-	if(!IsInRect(&rDims, x, y)) return 0L;
-	if(IsCloseToLine(&pts[0], &pts[1], x, y) ||
-		IsCloseToLine(&pts[2], &pts[3], x, y) ||
-		IsCloseToLine(&pts[3], &pts[4], x, y)){
-		if(dh1 && dh1->ObjThere(x, y)) return dh1;
-		if(dh2 && dh2->ObjThere(x, y)) return dh2;
-		return this;
-		}
-	return 0L;
-}
-
-void
-Arrow::Track(POINT *p, anyOutput *o)
-{
-	POINT *tpts;
-	RECT old_rc;
-	int i;
-
-	if(o && (tpts = (POINT*)malloc(6*sizeof(POINT)))){
-		memcpy(&old_rc, &rDims, sizeof(rDims));
-		o->UpdateRect(&rDims, false);
-		for(i = 0; i < 5; i++) {
-			tpts[i].x = pts[i].x+p->x;
-			tpts[i].y = pts[i].y+p->y;
-			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
-			}
-		switch(type & 0xff) {
-		case ARROW_LINE:
-			o->ShowLine(tpts+2, 3, LineDef.color);
-		case ARROW_NOCAP:
-			o->ShowLine(tpts, 2, LineDef.color);
-			break;
-		case ARROW_TRIANGLE:
-			tpts[5].x = tpts[2].x;		tpts[5].y = tpts[2].y;
-			o->ShowLine(tpts+2, 4, LineDef.color);
-			tpts[1].x = (tpts[2].x + tpts[4].x)>>1;
-			tpts[1].y = (tpts[2].y + tpts[4].y)>>1;
-			o->ShowLine(tpts, 2, LineDef.color);
-			break;
-			}
-		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
-			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
-		free(tpts);
-		}
-}
-
 void
 Arrow::Redraw(anyOutput *o)
 {
@@ -4507,9 +3612,8 @@ plane::DoClip(GraphObj *co)
 	//if two planes have the same parent it means they are part of one object
 	// do not clip!
 	if(co->parent == parent && co->Id == GO_PLANE) return;
-	if(co->Id == GO_PLANE && parent->parent->Id == GO_GRID3D 
+	if(co->Id == GO_PLANE && (parent->parent->Id == GO_GRID3D || parent->parent->Id == GO_RIBBON)
 		&& co->parent->parent == parent->parent) return;
-
 	cliprc.left = iround(co->GetSize(SIZE_MIN_X));
 	cliprc.right = iround(co->GetSize(SIZE_MAX_X));
 	cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
@@ -6308,97 +5412,20 @@ Label::RedrawEdit(anyOutput *o)
 	FillDEF bgFill = {FILL_NONE, bgcolor, 1.0, 0L, bgcolor};
 
 	if(!o || !parent) return;
-	bgLine.color = bgcolor;		o->SetLine(&bgLine);	o->SetFill(&bgFill);
-	o->oPolygon(pts, 5);		IncrementMinMaxRect(&rDims, 3);		
-	o->UpdateRect(&rDims, false);
-	CalcRect(o);				bgLine.color ^= 0x00ffffffL;
-	o->SetLine(&bgLine);		o->oPolygon(pts, 5);
-	if(parent->Id == GO_MLABEL) {
-		if(parent->parent && parent->parent->Id == GO_LEGITEM && parent->parent->parent)
-			parent->parent->parent->DoPlot(o);
-		else parent->DoPlot(o);
-		}
-	else if(parent->Id == GO_LEGITEM && parent->parent) parent->parent->DoPlot(o);
-	else DoPlot(o);
-	o->UpdateRect(&rDims, false);
-	DoMark(o, true);			ShowCursor(o);
-}
-
-void
-Label::ShowCursor(anyOutput *o)
-{
-	CalcRect(o);
-	ShowTextCursor(o, &Cursor, TextDef.ColTxt);
-}
-
-bool
-Label::AddChar(int ci, anyOutput *o)
-{
-	char c, *txt1 = 0L;
-	int i, j, k;
-	GraphObj *golist[2];
-
-	if(!o) return false;
-	if(ci == 13 && parent){		//CR
-		if(parent->Id == GO_MLABEL){
-			parent->Command(CMD_SETFOCUS, this, o);
-			return parent->Command(CMD_ADDCHAR, &ci, o);
-			}
-		if(golist[1] = new mLabel(parent, data, fPos.fx, fPos.fy, &TextDef, 
-			TextDef.text, CursorPos, flags)){
-			golist[1]->moveable = moveable;
-			golist[1]->SetSize(SIZE_LB_XDIST, fDist.fx);
-			golist[1]->SetSize(SIZE_LB_YDIST, fDist.fy);
-			}
-		golist[0] = this;
-		if(!parent->Command(CMD_MUTATE, golist, o)) DeleteGO(golist[1]);
-		return false;
-		}
-	if(ci < 254 && 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);
-		}
-	if(TextDef.text) txt1 = (char*)calloc((i = strlen(TextDef.text))+2, sizeof(char));
-	else txt1 = (char*)calloc((i = 0)+2, sizeof(char));
-	if(txt1) {
-		for(j = k = 0; j< i && j < CursorPos; txt1[k++] = TextDef.text[j++]);
-		txt1[k++] = c;
-		for(; j< i; txt1[k++] = TextDef.text[j++]);
-		if(TextDef.text) free(TextDef.text);
-		TextDef.text = txt1;
-		CursorPos++;		RedrawEdit(o);
-		}
-	return true;
-}
-
-void
-Label::CalcCursorPos(int x, int y, anyOutput *o)
-{
-	int i, j, ix, x1, y1, x2, h;
-
-	if(!o || !TextDef.text) return;
-	TextDef.iSize = o->un2iy(TextDef.fSize);
-	if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
-	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);
-		if(x1 <= ix && x2 >= ix) {
-			if((ix-x1) < (x2-ix)) CursorPos = i-1;
-			else CursorPos = i;
-			return;
-			}
-		else if(ix < x2){
-			CursorPos = i-1;
-			return;
-			}
-		x1 = x2;
+	bgLine.color = bgcolor;		o->SetLine(&bgLine);	o->SetFill(&bgFill);
+	o->oPolygon(pts, 5);		IncrementMinMaxRect(&rDims, 3);		
+	o->UpdateRect(&rDims, false);
+	CalcRect(o);				bgLine.color ^= 0x00ffffffL;
+	o->SetLine(&bgLine);		o->oPolygon(pts, 5);
+	if(parent->Id == GO_MLABEL) {
+		if(parent->parent && parent->parent->Id == GO_LEGITEM && parent->parent->parent)
+			parent->parent->parent->DoPlot(o);
+		else parent->DoPlot(o);
 		}
-	if(pts[3].x < pts[2].x && x < pts[3].x) CursorPos = 0;
-	else CursorPos = strlen(TextDef.text);
+	else if(parent->Id == GO_LEGITEM && parent->parent) parent->parent->DoPlot(o);
+	else DoPlot(o);
+	o->UpdateRect(&rDims, false);
+	DoMark(o, true);			ShowCursor(o);
 }
 
 void
@@ -7193,8 +6220,7 @@ polyline::Command(int cmd, void *tmpl, anyOutput *o)
 		switch (mev->Action) {
 		case MOUSE_LBUP:
 			if(!ObjThere(p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPoints <2)return false;
-			o->ShowMark(CurrGO=this, MRK_GODRAW);
-			break;
+			return o->ShowMark(CurrGO=this, MRK_GODRAW);
 			}
 		return false;
 	case CMD_DELOBJ:
@@ -7845,8 +6871,7 @@ rectangle::Command(int cmd, void *tmpl, anyOutput *o)
 		switch (mev->Action) {
 		case MOUSE_LBUP:
 			if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
-				o->ShowMark(this, MRK_GODRAW);
-				return true;
+				return o->ShowMark(this, MRK_GODRAW);
 				}
 			}
 		return false;
@@ -8660,7 +7685,8 @@ Graph::DoPlot(anyOutput *target)
 			}
 		if(GRect.Ymin > 0.0001 || GRect.Ymin < -0.0001) {
 			GRect.Ymax -= GRect.Ymin;	GRect.Ymin = 0.0;
-			}
+			}
+		bModified = false;			//first graph is not modified!
 		}
 	//the first output class is the display class
 	if(!Disp && (!(Disp = target))) return;
@@ -8728,19 +7754,6 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			else if(i == 1) if(! SaveGraphAs(this)) return false;
 			}
 		return true;
-	case CMD_CAN_DELETE:
-		HideTextCursor();
-		if(bModified) {
-			sprintf(TmpTxt, "%s has not been saved.\nDo you want to save it now?", name);
-			if(YesNoBox(TmpTxt)) SaveGraphAs(this);
-			}
-		bModified = false;
-		if(OwnDisp == true && Disp && CurrDisp){		//be careful not to reenter
-			OwnDisp = false;			DelDispClass(Disp);			
-			Disp = CurrDisp = 0L;		parent = 0L;
-			}
-		if(parent) parent->Command(CMD_DELOBJ, this, 0L);
-		return true;
 	case CMD_LAYERS:
 		Undo.SetDisp(o ? o : CurrDisp);
 		return ShowLayers(this);
@@ -8771,16 +7784,23 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 					}
 				}
 			if(!tmpl) {
-				if(!(tmpl = (void*) new Legend(this, data)))return false;
-				tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
-				if(!tmpPlots) return false;
-				Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-				Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
-				free(Plots);		Plots = tmpPlots;	bModified = true;
+				if(!(tmpl = (void*) new Legend(this, data)))return false;
+				if(Disp) {
+					Undo.SetDisp(Disp);
+					tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
+					if(!tmpPlots) return false;
+					Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+					Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+					free(Plots);		Plots = tmpPlots;	bModified = true;
+					}
+				else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+					Plots[NumPlots++] = (GraphObj*)tmpl;	Plots[NumPlots] = 0L;
+					}
+				else return false;
 				}
 			if(type == GT_CIRCCHART)((Legend*)tmpl)->SetSize(SIZE_XPOS, DRect.Xmin*3.0);
 			for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
-			Command(CMD_REDRAW, 0L, CurrDisp);
+			if(Disp) Command(CMD_REDRAW, 0L, CurrDisp);
 			}
 		return true;
 	case CMD_REPL_GO:
@@ -8981,7 +8001,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		bModified = true;
 		if(!tmpl) return false;
 		for(i = 0; i < NumAxes; i++) if(Axes[i] && (void*)Axes[i] == tmpl){
-			if(Axes[i]->Command(CMD_CAN_DELETE, 0L, o)) {
+			if(Axes[i]->Command(CMD_CAN_CLOSE, 0L, o)) {
 				Undo.DeleteGO((GraphObj**)(&Axes[i]), delflg, o);
 				return Command(CMD_REDRAW, 0L, o);
 				}
@@ -9009,15 +8029,20 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		tl_pts = 0L;	tl_nPts = 0;
 		if(CurrDisp) CurrDisp->MrkMode = MRK_NONE;
 		if(o) switch(ToolMode & 0x0f) {
-		case TM_TEXT:	o->MouseCursor(MC_TEXT, false);	break;
+		case TM_TEXT:	
+			o->MouseCursor(MC_TEXT, false);			break;
 		case TM_DRAW:		case TM_POLYLINE:		case TM_POLYGON:
-		case TM_RECTANGLE:	case TM_ELLIPSE:		case TM_ROUNDREC:
+			o->MouseCursor(MC_DRAWPEN, false);		break;
+		case TM_RECTANGLE:	
+			o->MouseCursor(MC_DRAWREC, false);		break;
+		case TM_ELLIPSE:		
+			o->MouseCursor(MC_DRAWELLY, false);		break;
+		case TM_ROUNDREC:
+			o->MouseCursor(MC_DRAWRREC, false);		break;
 		case TM_ARROW:
-			o->MouseCursor(MC_CROSS, false);
-			break;
+			o->MouseCursor(MC_CROSS, false);		break;
 		default:
-			o->MouseCursor(MC_ARROW, true);
-			break;
+			o->MouseCursor(MC_ARROW, true);			break;
 			}
 		return Command(CMD_REDRAW, 0L, CurrDisp);
 	case CMD_ADDPLOT:
@@ -9098,12 +8123,25 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		if(parent) return parent->Command(cmd, tmpl, o);
 		return false;
 	case CMD_DROP_PLOT:
-		if(!tmpl || ((GraphObj*)tmpl)->Id < GO_PLOT) return false;
+		if(!tmpl) return false;
+		((GraphObj*)tmpl)->parent = this;
+		if(((GraphObj*)tmpl)->Id < GO_PLOT) {
+			if(!NumPlots && Id != GO_PAGE) return false;
+			Plots = (GraphObj**)realloc(Plots, (NumPlots+2)*sizeof(GraphObj*));
+			Plots[NumPlots] = (GraphObj*)tmpl;
+			NumPlots++;
+			if(CurrDisp) {
+				CurrDisp->StartPage();
+				DoPlot(CurrDisp);
+				CurrDisp->EndPage();
+				}
+			return true;
+			}
 		if(Id == GO_GRAPH) CurrGraph = this;	bModified =true;
 		if(!NumPlots) {
 			Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
 			if(Plots) {
-				Plots[0] = (Plot *)tmpl;
+				Plots[0] = (Plot *)tmpl;	Plots[0]->parent = this;
 				switch(Plots[0]->Id) {
 				case GO_PIECHART:		case GO_RINGCHART:	case GO_STARCHART:
 					type = GT_CIRCCHART;
@@ -9151,11 +8189,18 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			return false;
 			}
-		else {
-			tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
-			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-			Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
-			free(Plots);			Plots = tmpPlots;
+		else {
+			if(Disp) {
+				Undo.SetDisp(Disp);
+				tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
+				Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+				Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+				free(Plots);			Plots = tmpPlots;
+				}
+			else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+				Plots[NumPlots++] = (Plot*)tmpl;	Plots[NumPlots] = 0L;
+				}
+			else return false;
 			if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) || 
 				(y_axis.flags & AXIS_AUTOSCALE))) {
 				if(x_axis.flags & AXIS_AUTOSCALE) {
@@ -9178,10 +8223,12 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 					}
 				}
 			dirty = false;
-			//Redraw graph to show all plots
-			CurrDisp->StartPage();
-			DoPlot(CurrDisp);
-			CurrDisp->EndPage();
+			//Redraw graph to show all plots
+			if(CurrDisp) {
+				CurrDisp->StartPage();
+				DoPlot(CurrDisp);
+				CurrDisp->EndPage();
+				}
 			return true;
 			}
 		break;
@@ -9642,524 +8689,6 @@ Graph::CreateAxes(int templ)
 		}
 }
 
-bool
-Graph::ExecTool(MouseEvent *mev)
-{
-	static POINT pl = {0, 0}, pc = {0, 0};
-	static DWORD color = 0L;
-	POINT line[5];
-	GraphObj **tmpPlots, *new_go;
-	TextDEF *td;
-	lfPOINT *lfp, lf;
-	int i, j;
-	double x, y;
-
-	if(!mev || !CurrDisp) return false;
-	td = 0L;
-	if(ToolMode & TM_MOVE) switch (mev->Action) {
-		case MOUSE_LBDOWN:
-			pl.x = pc.x = mev->x;				pl.y = pc.y = mev->y;
-			if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp)) return true;
-			CurrDisp->HideMark();			CurrDisp->MouseCursor(MC_MOVE, false);
-			return true;
-		case MOUSE_MOVE:
-			if(TrackGO) {
-				if(TrackGO->Id == GO_DRAGHANDLE && TrackGO->type >= DH_18 &&
-					TrackGO->type <= DH_88) {
-					lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));	
-					lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
-					TrackGO->Track((POINT*)&lf, CurrDisp);
-					}
-				else {
-					pc.x = mev->x-pl.x;				pc.y = mev->y-pl.y;
-					TrackGO->Track(&pc, CurrDisp);
-					}
-				}
-			return true;
-		case MOUSE_LBUP:
-			if(TrackGO) {
-				ToolMode &= ~TM_MOVE;
-				pc.x = mev->x-pl.x;				pc.y = mev->y-pl.y;
-				if(!pc.x && !pc.y){
-					Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
-					return false;
-					}
-				TrackGO->Track(&pc, CurrDisp);
-				lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));	
-				lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
-				TrackGO->Command(CMD_MOVE, &lf, CurrDisp);
-				bModified = true;
-				}
-			Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
-			return true;
-		default:
-			return true;
-		}
-	if(ToolMode == TM_MARK || ToolMode == TM_ZOOMIN) {
-		switch (mev->Action) {
-		case MOUSE_LBDOWN:			//we should not receive that !
-			rc_mrk.left = mev->x;	rc_mrk.top = mev->y;
-			return false;
-		case MOUSE_LBUP:
-			j = (i = rc_mrk.left - mev->x)*i;
-			j += ((i = rc_mrk.top - mev->y)*i);
-			if(j < 20) {						//glitch
-				rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = 0;
-				ToolMode = TM_STANDARD;		CurrDisp->MouseCursor(MC_ARROW, false);
-				return false;
-				}
-			if(ToolMode == TM_ZOOMIN) {
-				rc_mrk.right = mev->x;	rc_mrk.bottom = mev->y;
-				ToolMode = TM_STANDARD;
-				return Command(CMD_ZOOM, (void*) &"+", 0L);
-				}
-		default:
-			ToolMode = TM_STANDARD;
-		case MOUSE_MOVE:
-			if((mev->StateFlags &1) && rc_mrk.left >= 0 && rc_mrk.top >= 0) {
-				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
-					CurrDisp->UpdateRect(&rcUpd, false);
-				line[0].x = line[3].x = line[4].x = rc_mrk.left;
-				line[0].y = line[1].y = line[4].y = rc_mrk.top;
-				line[1].x = line[2].x = mev->x;
-				line[2].y = line[3].y = mev->y;
-				CurrDisp->ShowLine(line, 5, 0x00c0c0c0L);
-				rcUpd.left = rcUpd.right = rc_mrk.left;
-				rcUpd.top = rcUpd.bottom = rc_mrk.top;
-				UpdateMinMaxRect(&rcUpd, rc_mrk.right = mev->x, rc_mrk.bottom = mev->y);
-				IncrementMinMaxRect(&rcUpd,2);
-				}
-			return true;
-			}
-		}
-	if(ToolMode == TM_PASTE) {
-		switch (mev->Action) {
-		case MOUSE_LBUP:
-			ToolMode = TM_STANDARD;			CurrDisp->MouseCursor(MC_ARROW, false);
-			break;
-			}
-		return true;
-		}
-	if(NumPlots && !Plots[NumPlots-1]) {
-		Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
-		for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
-		NumPlots = j;
-		}
-	else if(!Plots && !(Plots = (GraphObj**)calloc(2, sizeof(GraphObj*))))return false;
-	else if(Plots[NumPlots]){
-		if(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2) * sizeof(GraphObj*), 0L)){
-			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-			free(Plots);	Plots = tmpPlots;
-			Plots[NumPlots] = Plots[NumPlots+1] = 0L;
-			}
-		else return false;
-		}
-	switch(ToolMode & 0x0f) {
-	case TM_DRAW:
-		switch (mev->Action) {
-		case MOUSE_LBDOWN:
-			CurrGO = 0L;
-			CurrDisp->MrkMode = MRK_NONE;
-			Command(CMD_REDRAW, 0L, CurrDisp);
-			color = defs.Color(COL_POLYLINE);
-			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
-			if(tl_pts) free(tl_pts);
-			tl_nPts = 0;
-			if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
-				AddToPolygon(&tl_nPts, tl_pts, &pc);
-			return true;
-		case MOUSE_LBUP:
-			pl.x = mev->x;				pl.y = mev->y;
-			if(tl_pts) AddToPolygon(&tl_nPts, tl_pts, &pc);
-			// create line object
-			if(tl_pts && tl_nPts >1) {			//DEBUG: check for plausibility
-				if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
-					for(i = 0; i < tl_nPts; i++) {
-						lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x - CurrDisp->VPorg.fx);	
-						lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y - CurrDisp->VPorg.fy);
-						}
-					if(Plots[NumPlots]) i = NumPlots+1;
-					else i = NumPlots;
-//					Undo.SetGO(this, &Plots[i], new polyline(this, data, lfp, (int)tl_nPts), 0L);
-					Undo.SetGO(this, &Plots[i], new Bezier(this, data, lfp, (int)tl_nPts, 0,
-							(CurrDisp->hres/CurrDisp->VPscale+CurrDisp->vres/CurrDisp->VPscale)/2.0), 0L);
-					if(Plots[i]){
-						NumPlots = i+1;
-						Plots[i]->moveable = 1;
-						Plots[i]->DoPlot(CurrDisp);							//init
-						CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
-						bModified = true;
-						}
-					free(lfp);
-					}
-				if(tl_pts) free(tl_pts);	tl_pts = 0L;	tl_nPts = 0;
-				return true;
-				}
-			if(tl_pts) free(tl_pts);	tl_pts = 0L;	tl_nPts = 0;
-			return false;
-		case MOUSE_MOVE:
-			if((mev->StateFlags &1) && tl_pts && tl_nPts < 4095) {
-				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);
-				return true;
-				}
-			break;
-			}
-		break;
-	case TM_POLYLINE:
-	case TM_POLYGON:
-		switch (mev->Action) {
-		case MOUSE_LBDOWN:
-			if(!tl_pts) {
-				CurrGO = 0L;
-				CurrDisp->MrkMode = MRK_NONE;
-				Command(CMD_REDRAW, 0L, CurrDisp);
-				color = defs.Color((ToolMode & 0x0f) == TM_POLYLINE ? COL_POLYLINE : COL_POLYGON);
-				pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
-				tl_nPts = 0;
-				if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
-				AddToPolygon(&tl_nPts, tl_pts, &pc);
-				rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
-				rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
-				}
-			return true;
-		case MOUSE_MOVE:
-			if(tl_pts && tl_nPts) {
-				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
-					CurrDisp->UpdateRect(&rcUpd, false);
-				CurrDisp->ShowLine(tl_pts, tl_nPts, color);
-				line[1].x = mev->x;				line[1].y = mev->y;
-				line[0].x = pc.x;				line[0].y = pc.y;
-				CurrDisp->ShowLine(line, 2, color);
-				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
-				memcpy(&rcUpd, &rcDim, sizeof(RECT));
-				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
-				IncrementMinMaxRect(&rcUpd, 2);
-				return true;
-				}
-			break;
-		case MOUSE_LBUP:
-			if(tl_pts && tl_nPts) {
-				memcpy(&pl, &pc, sizeof(POINT));
-				pc.x = mev->x;				pc.y = mev->y;
-				UpdateMinMaxRect(&rcDim, mev->x, mev->y);
-				AddToPolygon(&tl_nPts, tl_pts, &pc);
-				}
-			return true;
-		default:			// create line or polygon object
-			if(tl_pts && tl_nPts >0) {			//DEBUG: check for plausibility
-				pc.x = mev->x;				pc.y = mev->y;
-				AddToPolygon(&tl_nPts, tl_pts, &pc);
-				if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
-					for(i = 0; i < tl_nPts; i++) {
-						lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x-CurrDisp->VPorg.fx);	
-						lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y-CurrDisp->VPorg.fy);
-						}
-					if(Plots[NumPlots]) i = NumPlots+1;
-					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;
-						Plots[i]->moveable = 1;
-						Plots[i]->DoPlot(CurrDisp);							//init
-						CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
-						bModified = true;
-						}
-					free(lfp);
-					}
-				free(tl_pts);			tl_pts = 0L;		tl_nPts = 0;
-				return true;
-				}
-			}
-		if(mev->x == pc.x && mev->y == pc.y) return true;	//rebounce
-		break;
-	case TM_RECTANGLE:	case TM_ELLIPSE:	case TM_ROUNDREC:	case TM_ARROW:
-		switch (mev->Action) {
-		case MOUSE_LBDOWN:
-			CurrGO = 0L;
-			CurrDisp->MrkMode = MRK_NONE;
-			Command(CMD_REDRAW, 0L, CurrDisp);
-			color = defs.Color((ToolMode & 0x0f) != TM_ARROW ? COL_POLYGON : COL_DATA_LINE);
-			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
-			rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
-			rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
-			return true;
-		case MOUSE_MOVE:
-			if(mev->StateFlags &1) {
-				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
-					CurrDisp->UpdateRect(&rcUpd, false);
-				line[0].x = line[4].x = pl.x;	line[0].y = line[4].y = pl.y;
-				if((ToolMode & 0x0f)==TM_ARROW) {
-					line[1].x = pc.x = mev->x;		line[1].y = pc.y = mev->y;
-					CurrDisp->ShowLine(line, 2, color);
-					}
-				else {
-					line[1].x = pc.x = mev->x;		line[1].y = pl.y;
-					line[2].x = mev->x;				line[2].y = pc.y = mev->y;
-					line[3].x = pl.x;				line[3].y = mev->y;
-					CurrDisp->ShowLine(line, 5, color);
-					if((ToolMode & 0x0f) == TM_ELLIPSE) 
-						CurrDisp->ShowEllipse(pc, pl, color);
-					}
-				memcpy(&rcUpd, &rcDim, sizeof(RECT));
-				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
-				IncrementMinMaxRect(&rcUpd, 2);
-				return true;
-				}
-			break;
-		case MOUSE_LBUP:
-			pc.x = mev->x;			pc.y = mev->y;
-			if(((ToolMode & 0x0f)==TM_ARROW || (abs(pc.x-pl.x) >5 && abs(pc.y-pl.y) >5)) && 
-				(lfp = (lfPOINT*)malloc(2 * sizeof(lfPOINT)))){
-				lfp[0].fx = CurrDisp->fix2un(pl.x - CurrDisp->VPorg.fx);
-				lfp[0].fy = CurrDisp->fiy2un(pl.y - CurrDisp->VPorg.fy);
-				lfp[1].fx = CurrDisp->fix2un(pc.x - CurrDisp->VPorg.fx);
-				lfp[1].fy = CurrDisp->fiy2un(pc.y - CurrDisp->VPorg.fy);
-				if(Plots[NumPlots]) i = NumPlots+1;
-				else i = NumPlots;
-				if(ToolMode == TM_RECTANGLE) new_go = new rectangle(this, data,
-					&lfp[0], &lfp[1]);
-				else if(ToolMode == TM_ELLIPSE) new_go = new ellipse(this, data,
-					&lfp[0], &lfp[1]);
-				else if(ToolMode == TM_ROUNDREC) new_go = new roundrec(this, data,
-					&lfp[0], &lfp[1]);
-				else if(ToolMode == TM_ARROW) new_go = new Arrow(this, data,
-					lfp[0], lfp[1], ARROW_UNITS | ARROW_LINE);
-				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
-					Plots[i]->moveable = 1;
-					bModified = true;
-					}
-				free(lfp);
-				}
-			else if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom) {
-				CurrDisp->UpdateRect(&rcUpd, false);
-				}
-			}
-		break;
-	case TM_TEXT:
-		if(Plots[NumPlots]) i = NumPlots+1;
-		else i = NumPlots;
-		switch(mev->Action) {
-		case MOUSE_LBUP:
-			if(!(td = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
-			x = CurrDisp->fix2un(mev->x-CurrDisp->VPorg.fx);
-			y = CurrDisp->fiy2un(mev->y-CurrDisp->VPorg.fy);
-			td->ColTxt = defs.Color(COL_TEXT);		td->ColBg = defs.Color(COL_BG);
-			td->RotBL = td->RotCHAR = 0.0f;			td->fSize = defs.GetSize(SIZE_TEXT);
-			td->Align = TXA_VTOP | TXA_HLEFT;		td->Style = TXS_NORMAL;
-			td->Mode = TXM_TRANSPARENT;				td->Font = FONT_HELVETICA;
-			td->text = 0L;
-			CurrGO = 0L;
-			CurrDisp->MrkMode = MRK_NONE;
-			Command(CMD_REDRAW, 0L, CurrDisp);
-			y -= td->fSize/2.0;
-			Undo.SetGO(this, &Plots[i], new Label(this, data, x, y, td, 0L), 0L);
-			if(Plots[i]){
-				NumPlots = i+1;
-				Plots[i]->DoPlot(CurrDisp);							//init
-				CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
-				Plots[i]->moveable = 1;
-				}
-			free(td);
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-bool
-Graph::MoveObj(int cmd, GraphObj *g)
-{
-	int i, j;
-	GraphObj *g1 = 0;
-
-	if(!g || NumPlots <2 || g->parent != this) return false;
-	switch(cmd) {
-	case CMD_MOVE_TOP:
-		for(i = j = 0; i <NumPlots; i++){
-			if(g == Plots[i]) g1 = Plots[i];
-			else Plots[j++] = Plots[i];
-			}
-		if(g1) {
-			Plots[j++] = g1;
-			return true;
-			}
-		break;
-	case CMD_MOVE_UP:
-		for(i = 0; i<NumPlots-1; i++){
-			if(g == Plots[i]){
-				g1 = Plots[i];	Plots[i] = Plots[i+1];	Plots[i+1] = g1;
-				return true;
-				}
-			}
-		break;
-	case CMD_MOVE_DOWN:
-		for(i = 1; i<NumPlots; i++){
-			if(g == Plots[i]){
-				g1 = Plots[i];	Plots[i] = Plots[i-1];	Plots[i-1] = g1;
-				return true;
-				}
-			}
-		break;
-	case CMD_MOVE_BOTTOM:
-		if(Plots[0] == g) return false;
-		for(i =  j = NumPlots-1; i >= 0; i--) {
-			if(g == Plots[i]) g1 = Plots[i];
-			else Plots[j--] = Plots[i];
-			}
-		if(g1) {
-			Plots[j--] = g1;
-			return true;
-			}
-		break;
-		}
-	return false;
-}
-
-bool
-Graph::DoZoom(char *z)
-{
-	RECT cw;
-	double fac, f1, f2;
-	ZoomDEF *tz;
-	Graph *cg;
-
-	if(!z) return false;
-	if(0==strcmp("fit", z)) {
-		if(CurrGraph) cg = CurrGraph;
-		else cg = this;
-		rc_mrk.left = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_LEFT))-4;
-		rc_mrk.right = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_RIGHT))+4
-			+ iround(CurrDisp->MenuHeight);
-		rc_mrk.top = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_TOP))-4 
-			- iround(CurrDisp->MenuHeight);
-		rc_mrk.bottom = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_BOTTOM))+4;
-		CurrDisp->ActualSize(&cw);
-		f1 = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
-		f2 = ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
-		fac = f1 < f2 ? f1 : f2;
-		if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
-		if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
-		if(fac == 1.0) return false;
-		if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
-			if(zoom_def) free(zoom_def);
-			zoom_def = tz;
-			zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
-			zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
-			zoom_def[zoom_level].scale = CurrDisp->VPscale;
-			zoom_level++;
-			}
-		CurrDisp->VPscale *= fac;
-		if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05; 
-		if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0; 
-		CurrDisp->VPorg.fx = -rc_mrk.left * fac;
-		CurrDisp->VPorg.fy = -rc_mrk.top * fac;
-		HideTextCursor();
-		Command(CMD_SETSCROLL, 0L, CurrDisp);
-		return true;
-		}
-	else if(0==strcmp("+", z)) {
-		if(rc_mrk.left >= 0 && rc_mrk.right >= 0 && rc_mrk.top >= 0 && rc_mrk.bottom >= 0) {
-			if(rc_mrk.left > rc_mrk.right) Swap(rc_mrk.left, rc_mrk.right);
-			if(rc_mrk.top > rc_mrk.bottom) Swap(rc_mrk.top, rc_mrk.bottom);
-			if(5 > (rc_mrk.right - rc_mrk.left) || 5 > (rc_mrk.bottom - rc_mrk.top)) {
-				rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
-				ToolMode = TM_STANDARD;		Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
-				return false;
-				}
-			CurrDisp->ActualSize(&cw);
-			fac = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
-			fac += ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
-			fac /= 2.0;
-			if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
-			if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
-			if(fac == 1.0) return false;
-			if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
-				if(zoom_def) free(zoom_def);
-				zoom_def = tz;
-				zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
-				zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
-				zoom_def[zoom_level].scale = CurrDisp->VPscale;
-				zoom_level++;
-				}
-			CurrDisp->VPscale *= fac;
-			if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05; 
-			if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0; 
-			CurrDisp->VPorg.fx = CurrDisp->VPorg.fx * fac - rc_mrk.left * fac;
-			CurrDisp->VPorg.fy = CurrDisp->VPorg.fy * fac - rc_mrk.top * fac;
-			HideTextCursor();
-			Command(CMD_SETSCROLL, 0L, CurrDisp);
-			CurrDisp->MouseCursor(MC_ARROW, false);
-			rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
-			ToolMode = TM_STANDARD;		Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
-			return true;
-			}
-		else {
-			ToolMode = TM_ZOOMIN;			CurrDisp->MouseCursor(MC_ZOOM, true);
-			}
-		}
-	else if(0==strcmp("-", z)) {
-		HideTextCursor();
-		if(zoom_def && zoom_level > 0) {
-			zoom_level--;
-			if(CurrDisp->VPscale == zoom_def[zoom_level].scale &&
-				CurrDisp->VPorg.fx == zoom_def[zoom_level].org.fx &&
-				CurrDisp->VPorg.fy == zoom_def[zoom_level].org.fy) {
-				DoZoom(z);
-				}
-			else {
-				CurrDisp->VPscale = zoom_def[zoom_level].scale;
-				CurrDisp->VPorg.fx = zoom_def[zoom_level].org.fx;
-				CurrDisp->VPorg.fy = zoom_def[zoom_level].org.fy;
-				}
-			}
-		else {
-			CurrDisp->VPorg.fx = CurrDisp->VPorg.fy = 0.0;
-			CurrDisp->VPscale = Id == GO_PAGE ? 0.5 : 1.0;
-			}
-		Command(CMD_SETSCROLL, 0L, CurrDisp);
-		return true;
-		}
-	else if(0==strcmp("25", z)){
-		CurrDisp->VPscale = 0.25;		return DoZoom("org");
-		}
-	else if(0==strcmp("50", z)){
-		CurrDisp->VPscale = 0.50;		return DoZoom("org");
-		}
-	else if(0==strcmp("100", z)){
-		CurrDisp->VPscale = 1.00;		return DoZoom("org");
-		}
-	else if(0==strcmp("200", z)){
-		CurrDisp->VPscale = 2.00;		return DoZoom("org");
-		}
-	else if(0==strcmp("400", z)){
-		CurrDisp->VPscale = 4.00;		return DoZoom("org");
-		}
-	else if(0==strcmp("org", z)){
-		CurrDisp->VPorg.fx = 0.0;		CurrDisp->VPorg.fy = iround(CurrDisp->MenuHeight);
-		HideTextCursor();
-		Command(CMD_SETSCROLL, 0L, CurrDisp);
-		return DoZoom("reset");
-		}
-	else if(0==strcmp("reset", z)){
-		if(zoom_def && zoom_level > 0) free(zoom_def);
-		zoom_def = 0L;			zoom_level = 0;
-		}
-	return false;
-}
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Pages are graphic objects containing graphs and drawn objects
 Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L)
@@ -10235,12 +8764,18 @@ Page::Command(int cmd, void *tmpl, anyOutput *o)
 		return true;
 	case CMD_CONFIG:
 		return Configure();
-	case CMD_DROP_GRAPH:
-		if(!(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2)*sizeof(GraphObj*), 0))) 
-			return false;
-		Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
-		free(Plots);			Plots = tmpPlots;	Plots[NumPlots] = Plots[NumPlots+1] = 0L;
-		Undo.SetGO(this, &Plots[NumPlots], (GraphObj*)tmpl, 0L);
+	case CMD_DROP_GRAPH:
+		if(Disp) {
+			if(!(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2)*sizeof(GraphObj*), 0))) 
+				return false;
+			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+			free(Plots);			Plots = tmpPlots;	Plots[NumPlots] = Plots[NumPlots+1] = 0L;
+			Undo.SetGO(this, &Plots[NumPlots], (GraphObj*)tmpl, 0L);
+			}
+		else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+			Plots[NumPlots] = (GraphObj*)tmpl;	Plots[NumPlots+1] = 0L;
+			}
+		else return false;
 		if(Plots[NumPlots]){
 			Plots[NumPlots]->parent = this;
 			Plots[NumPlots]->Command(CMD_SET_DATAOBJ, data, 0L);
@@ -10266,128 +8801,3 @@ Page::Command(int cmd, void *tmpl, anyOutput *o)
 	}
 }
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a tree structure of all interesting objects
-//   This object is used e.g. for layer control
-ObjTree::ObjTree(GraphObj *par, DataObj *d, GraphObj *root):GraphObj(par, d)
-{
-	Id = GO_OBJTREE;					base = root;		list=0L;
-	TextDef.ColTxt = 0x00000000L;		TextDef.ColBg = 0x00ffffffL;
-	TextDef.fSize = 4.0;				TextDef.RotBL = TextDef.RotCHAR = 0.0;
-	TextDef.iSize = 0;					TextDef.Align = TXA_HLEFT | TXA_VTOP;
-	TextDef.Mode = TXM_TRANSPARENT;		TextDef.Style = TXS_NORMAL;
-	TextDef.Font = FONT_HELVETICA;		TextDef.text = 0L;
-	Command(CMD_LAYERS, 0L, 0L);
-}
-
-ObjTree::~ObjTree()
-{
-	if(list) free(list);		list = 0L;
-}
-
-void
-ObjTree::DoPlot(anyOutput *o)
-{
-	int i, n, ix, iy;
-	GraphObj *curr_obj;
-
-	if(!o || !list) return;
-	o->Erase(0x00ffffffL);
-	ix = 10;	iy = 0;
-	for(i = 0; i < count; i++, iy += (TextDef.iSize+_SBINC)) {
-		if(list[i]) {
-			curr_obj = list[i];			n = 0;
-			if(i) while(curr_obj && curr_obj != list[0]) {
-				if(curr_obj != list[0]) n += sprintf(TmpTxt + n, " -");
-				if(curr_obj) curr_obj = curr_obj->parent; 
-				}
-			sprintf(TmpTxt + n, "%s%s", n ? " " : "", get_name(i));
-			if(list[i]->Id >= GO_PLOT && list[i]->Id < GO_GRAPH) {
-				TextDef.ColTxt = ((Plot*)list[i])->hidden ? 0x00000080L : 0x00008000L;
-				}
-			else TextDef.ColTxt = 0x00000000L;
-			o->SetTextSpec(&TextDef);
-			o->oTextOut(ix, iy, TmpTxt, 0);
-			}
-		}
-}
-
-bool
-ObjTree::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	switch(cmd){
-	case CMD_LAYERS:
-		if(list) free(list);
-		count = 0;		maxcount = 100;
-		if(base) {
-			if(list = (GraphObj**) malloc(100 * sizeof(GraphObj*))) {
-				list[count++] = base;
-				}
-			base->Command(CMD_OBJTREE, this, 0L);
-			}
-		break;
-	case CMD_SET_DATAOBJ:
-		Id = GO_OBJTREE;
-		return true;
-	case CMD_UPDATE:
-		if(tmpl && (((GraphObj*)tmpl)->Id >= GO_PLOT && ((GraphObj*)tmpl)->Id < GO_SPREADDATA)
-			|| ((GraphObj*)tmpl)->Id == GO_LEGEND) {
-			if(count >= maxcount) {
-				maxcount += 100;
-				list = (GraphObj**) realloc(list, maxcount);
-				}
-			if(list) list[count++] = (GraphObj*)tmpl;
-			}
-		return true;
-	case CMD_TEXTDEF:
-		if(tmpl) memcpy(&TextDef, tmpl, sizeof(TextDEF));
-		TextDef.text = 0L;
-		return true;
-		}
-	return false;
-}
-
-anyOutput *
-ObjTree::CreateBitmap(int *bw, int *bh, anyOutput *tmpl)
-{
-	anyOutput *bmp = 0L;
-	int h;
-	
-	h = tmpl->un2iy(TextDef.fSize) * count;
-	if(h > *bh) *bh = h;
-	if(bmp = NewBitmapClass(*bw, *bh, tmpl->hres, tmpl->vres)) DoPlot(bmp);
-	return bmp;
-}
-
-char *
-ObjTree::get_name(int li)
-{
-	if(li < count && list[li] && list[li]->name) return list[li]->name;
-	else return "(unknown)";
-}
-
-int
-ObjTree::get_vis(int li)
-{
-	if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH)
-		return ((Plot*)list[li])->hidden ? 0 : 1;
-	return 2;
-}
-
-bool
-ObjTree::set_vis(int li, bool vis)
-{
-	if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH) {
-		((Plot*)list[li])->hidden = vis ? 0 : 1;
-		list[li]->Command(CMD_MRK_DIRTY, 0L, 0L);
-		list[li]->Command(CMD_REDRAW, 0L, 0L);
-		}
-	return false;
-}
-
-GraphObj*
-ObjTree::get_obj(int li)
-{
-	if(li < count && list[li]) return list[li];
-	return 0L;
-}
diff --git a/rlplot.h b/rlplot.h
index 875f2de..e38a201 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -97,7 +97,7 @@ enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
 	CMD_BUBBLE_ATTRIB, CMD_BUBBLE_FILL, CMD_BUBBLE_LINE, CMD_DL_LINE, 
 	CMD_DL_TYPE, CMD_SEG_FILL, CMD_SEG_LINE, CMD_SELECT, CMD_MOVE, CMD_CUT,
 	CMD_SETSCROLL, CMD_SETHPOS, CMD_SETVPOS, CMD_PG_FILL, CMD_BOUNDS,
-	CMD_SHIFT_OUT, CMD_CAN_DELETE, CMD_CAN_CLOSE, CMD_RESET_LINE, CMD_SET_TICKSTYLE,
+	CMD_SHIFT_OUT, CMD_CAN_CLOSE, CMD_RESET_LINE, CMD_SET_TICKSTYLE,
 	CMD_GET_GRIDLINE, CMD_SET_GRIDLINE, CMD_SET_GRIDTYPE, CMD_TLB_TXTDEF,
 	CMD_DROP_LABEL, CMD_DROP_OBJECT, CMD_PAGEUP, CMD_PAGEDOWN, CMD_AUTOSCALE,
 	CMD_MRK_DIRTY, CMD_SETNAME, CMD_TOOLMODE, CMD_DROPFILE, CMD_AXIS, CMD_INIT,
@@ -150,7 +150,8 @@ enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
 	TM_ROUNDREC, TM_ARROW, TM_TEXT, TM_MARK, TM_ZOOMIN, TM_MOVE = 0x100, 
 	TM_PASTE=0x200};
 enum {MC_LAST, MC_ARROW, MC_CROSS, MC_TEXT, MC_WAIT, MC_MOVE, MC_NORTH,
-	MC_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM, MC_PASTE};
+	MC_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM, MC_PASTE, MC_DRAWPEN, MC_DRAWREC, 
+	MC_DRAWRREC, MC_DRAWELLY};
 enum {FILE_ERROR, FILE_READ, FILE_WRITE, INIT_VARS, SAVE_VARS};
 enum {ARROW_NOCAP, ARROW_LINE, ARROW_TRIANGLE, ARROW_UNITS = 0x100};
 enum {MENU_NONE, MENU_SPREAD, MENU_GRAPH, MENU_PAGE};
@@ -831,6 +832,7 @@ public:
 	void FileValues(char *name, int type, double start, double step);
 	void SetValues();
 	void LineData(lfPOINT *val, long nval);
+	void DrawCurve(anyOutput *target);
 	void DrawSpline(anyOutput *target);
 };
 
@@ -1848,6 +1850,7 @@ class Ribbon:public Plot {
 public:
 	Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char *yr);
 	Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr);
+	Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo);
 	Ribbon(int src);
 	~Ribbon();
 	double GetSize(int select);
@@ -2656,7 +2659,11 @@ double errf(double x);
 double errfc(double x);
 double norm_dist(double x, double m, double s);
 double norm_freq(double x, double m, double s);
+double exp_dist(double x, double l, double s);
+double exp_inv(double p, double l, double s);
+double exp_freq(double x, double l, double s);
 double lognorm_dist(double x, double m, double s);
+double lognorm_freq(double x, double m, double s);
 double chi_dist(double x, double df, double);
 double t_dist(double t, double df, double);
 double pois_dist(double x, double m, double);
@@ -2685,3 +2692,8 @@ bool date_value(char *desc, char *fmt, double *value);
 char *value_date(double dv, char *fmt);
 double now_today();
 void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s);
+Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *text1, char *text2, char *text3);
+
+//prototypes reports.cpp
+void rep_anova(GraphObj *parent, DataObj *data);
+void rep_regression(GraphObj *parent, DataObj *data);
diff --git a/spreadwi.cpp b/spreadwi.cpp
index 97b6824..d8c0ed5 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -153,7 +153,7 @@ SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
 {
 	d = Data;	g = 0L;		ssOrg.x =  ssOrg.y = 0;		NumGraphs = 0;
 	ch = 19;	cw = 76;	fw = 32;	filename=0L;	aButton = 0L;
-	w = 0L;
+	w = 0L;		cButtons = rButtons = 0L;
 	if(w = NewDispClass(this)){
 		w->hasHistMenu = true;
 		ssText.RotBL = ssText.RotCHAR = 0.0;
@@ -194,10 +194,7 @@ SpreadWin::~SpreadWin()
 		if (aButton) delete(aButton);
 		if (w) delete w;
 		if (g && NumGraphs) {
-			for(i = 0; i < NumGraphs; i++) if(g[i]) {
-				g[i]->Command(CMD_CAN_DELETE, 0L, 0L);
-				delete(g[i]);
-				}
+			for(i = 0; i < NumGraphs; i++) if(g[i]) delete(g[i]);
 			free (g);
 			}
 		if(filename) free(filename);	filename=0L;
@@ -256,15 +253,6 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 				else if(i == 1) return Command(CMD_SAVEDATAAS, tmpl, o);
 				}
 			return true;
-		case CMD_CAN_DELETE:
-			HideTextCursor();
-			if(is_modified==true && YesNoBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?")){
-				is_modified=false;
-				return Command(CMD_SAVEDATAAS, tmpl, o);
-				}
-			Undo.KillDisp(w);
-			is_modified=false;
-			return true;
 		case CMD_MRK_DIRTY:
 			return is_modified = true;
 		case CMD_WRITE_GRAPHS:
@@ -305,22 +293,20 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			return false;
 		case CMD_DELGRAPH:
 			if (g && NumGraphs) {
-				for(i = 0; i < NumGraphs; i++) if(g[i]){
-					g[i]->Command(CMD_CAN_DELETE, 0L, 0L);
-					DeleteGO(g[i]);
-					}
+				for(i = 0; i < NumGraphs; i++) if(g[i]) DeleteGO(g[i]);
 				free (g);
 				}
 			g = 0L;			NumGraphs = 0;		Undo.Flush();
 			return true;
 		case CMD_DELOBJ:
-			if(g && tmpl) for(i = j = 0; i < NumGraphs; i++) {
+			i = j = 0;
+			if(g && tmpl) for(; i < NumGraphs; i++) {
 				if(g[i] == (Graph*) tmpl) {
 					DeleteGO(g[i]);
 					}
 				else (g[j++] = g[i]);
 				}
-			if(j < i) g[j] = 0L;				NumGraphs = j;
+			if(g && j < i) g[j] = 0L;			NumGraphs = j;
 			return true;
 		case CMD_SAVEDATA:
 			if(o) o->MouseCursor(MC_WAIT, false);
@@ -364,7 +350,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(DoSpShSize(d)) DoPlot(o);
 			return true;
 		case CMD_MOUSE_EVENT:
-			if(o && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
+			if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
 				if(mev->x < fw && mev->y < (o->MenuHeight + ch) && aButton) {
 					aButton->Command(cmd, tmpl, o);
 					}
@@ -832,7 +818,7 @@ SpreadData::Init(int nRows, int nCols)
 	RECT rc;
 
 	cRows = nRows;	cCols = nCols;				currpos.x = currpos.y = 0;
-	new_mark = bCopyCut = false;
+	new_mark = bCopyCut = false;				if(w && m_range) HideMark(true);
 	if(!Disp) {
 		Disp = new SpreadWin(g_parent, this);
 		w = Disp->w;
@@ -1076,7 +1062,7 @@ SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
 	POINT pt;
 
 	if(FileName) {		//read disk file
-		Disp->Command(CMD_CAN_DELETE, 0L, 0L);
+		if(!Disp->Command(CMD_CAN_CLOSE, 0L, 0L))return false;
 		if(0 == strcmp(".xml", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".XML", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
diff --git a/use_gui.cpp b/use_gui.cpp
new file mode 100755
index 0000000..023f00e
--- /dev/null
+++ b/use_gui.cpp
@@ -0,0 +1,1656 @@
+//use_gui.cpp, Copyright 2000-2006 R.Lackner
+//
+//    This file is part of RLPlot.
+//
+//    RLPlot is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or
+//    (at your option) any later version.
+//
+//    RLPlot is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with RLPlot; if not, write to the Free Software
+//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This modules contains code for builds using a graphical user interface.
+// Builds running without GUI use no_gui.cpp instead.
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char TmpTxt[];
+extern Default defs;
+extern GraphObj *CurrGO, *TrackGO;			//Selected Graphic Objects
+extern Graph *CurrGraph;
+extern dragHandle *CurrHandle;
+extern UndoObj Undo;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Spread sheet buttons used for rows and columns
+ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
+{
+	bLBdown = bSelected = bMarked = false;
+	SetMinMaxRect(&rDims, x, y, x+w, y+h);
+	Line.width = 0.0f;				Line.patlength = 1.0f;
+	Line.color = 0x00000000L;		Line.pattern = 0x00000000L;
+	Fill.type = FILL_NONE;			Fill.color = 0x00e8e8e8L;
+	Fill.scale = 1.0;				Fill.hatch = NULL;
+	TextDef.ColTxt = 0x00000000L;	TextDef.ColBg = 0x00ffffffL;
+	TextDef.fSize = 4.0;			TextDef.RotBL = TextDef.RotCHAR = 0.0;
+	TextDef.iSize = 0;				TextDef.Align = TXA_HLEFT | TXA_VTOP;
+	TextDef.Mode = TXM_TRANSPARENT;	TextDef.Style = TXS_NORMAL;
+	TextDef.Font = FONT_HELVETICA;	TextDef.text = 0L;
+}
+
+ssButton::~ssButton()
+{
+	if(TextDef.text) free(TextDef.text);
+}
+
+void
+ssButton::DoPlot(anyOutput *o)
+{
+	POINT pts[3];
+
+	Line.color = 0x00000000L;
+	if(bSelected) {
+		Fill.color = bMarked ? 0x00ffffe0L : 0x00ffffffL;
+		}
+	else {
+		Fill.color = bMarked ? 0x00ffe0e0L : 0x00e8e8e8L;
+		}
+	o->SetLine(&Line);				o->SetFill(&Fill);
+	if(bLBdown){
+		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+		}
+	else {
+		o->oRectangle(rDims.left, rDims.top, rDims.right-1, rDims.bottom-1);
+		Line.color = 0x00000000L;
+		o->SetLine(&Line);
+		pts[0].x = rDims.left;					pts[0].y = pts[1].y = rDims.bottom-1;
+		pts[1].x = pts[2].x = rDims.right-1;	pts[2].y = rDims.top-1;
+		o->oPolyline(pts, 3);
+		Line.color = 0x00ffffffL;
+		o->SetLine(&Line);
+		pts[0].x = pts[1].x = rDims.left;		pts[0].y = rDims.bottom -3;
+		pts[1].y = pts[2].y = rDims.top;		pts[2].x = rDims.right -2;
+		o->oPolyline(pts, 3);
+		}
+	if(TextDef.text) {
+		o->SetTextSpec(&TextDef);
+#ifdef _WINDOWS
+		o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2-1, TextDef.text, 0);
+#else
+		o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2+1, TextDef.text, 0);
+#endif
+		}
+
+}
+void
+ssButton::DoMark(anyOutput *o, bool mark)
+{
+	bLBdown = mark;
+	DoPlot(o);
+	o->UpdateRect(&rDims, false);
+}
+
+bool
+ssButton::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	char *tmptxt;
+	MouseEvent *mev;
+
+	switch (cmd) {
+	case CMD_GETTEXT:
+		if(TextDef.text && tmpl) {
+			strcpy((char*)tmpl, TextDef.text);
+			return true;
+			}
+		return false;
+	case CMD_SELECT:
+		if(tmpl && *((int*)tmpl)) bSelected = true;
+		else bSelected = false;
+		if(o) {
+			DoPlot(o);
+			o->UpdateRect(&rDims, false);
+			}
+		return true;
+	case CMD_SETSTYLE:
+		if(tmpl && *((int*)tmpl)) bMarked = true;
+		else bMarked = false;
+		if(o) {
+			DoPlot(o);		o->UpdateRect(&rDims, false);
+			}
+		return true;
+	case CMD_SETTEXT:
+		if(TextDef.text) free(TextDef.text);
+		if(tmpl) TextDef.text = strdup((char*)tmpl);
+		else TextDef.text = 0L;
+		return true;
+	case CMD_GETTEXTDEF:
+		if(!tmpl) return false;
+		memcpy(tmpl, &TextDef, sizeof(TextDEF));
+		return true;
+	case CMD_SETTEXTDEF:
+		if(!tmpl)return false;
+		tmptxt = TextDef.text;
+		memcpy(&TextDef, tmpl, sizeof(TextDEF));
+		TextDef.text = tmptxt;
+		return true;
+	case CMD_MOUSE_EVENT:
+		if(!o || !(mev = (MouseEvent *) tmpl)) break;
+		if(IsInRect(&rDims, mev->x, mev->y)) {
+			if(bLBdown) {
+				if(!(mev->StateFlags & 0x01)) {
+					o->HideMark();
+					if(bLBdown) {
+						bLBdown = false; DoPlot(o);
+						}
+					}
+				}
+			else if(mev->StateFlags & 0x01) {
+				o->ShowMark(this, MRK_SSB_DRAW);
+				}
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// drag handles are graphic objects which allow the user to interactively
+//   change the size of an object
+dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
+{
+	type = which;
+	Id = GO_DRAGHANDLE;
+	LineDef.width = LineDef.patlength = 0.0;
+	LineDef.color = LineDef.pattern = 0L;
+	FillDef.type = FILL_NONE;
+	FillDef.color = 0x00ffffffL;
+	FillDef.scale = 1.0;
+	FillDef.hatch = 0L;
+	minRC = maxRC = 0L;
+}
+
+dragHandle::~dragHandle()
+{
+	if(minRC) free(minRC);
+	if(maxRC) free(maxRC);
+	if(CurrHandle == this) CurrHandle = 0L;
+}
+
+void
+dragHandle::DoPlot(anyOutput *o)
+{
+	double fx, fy, dx, dy;
+	int ix, iy, idx;
+	fPOINT3D fp3d, ifp3d;
+	bool is3D = false;
+
+	if(!o || !parent) return;
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	SetMinMaxRect(&drec, o->co2ix(parent->GetSize(SIZE_XPOS)+dx), 
+		o->co2iy(parent->GetSize(SIZE_YPOS)+dy), o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx),
+		o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy));
+	switch(type) {
+	case DH_19:		case DH_12:
+		fx = parent->GetSize(SIZE_XPOS);	fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_99:		case DH_22:
+		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_29:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_39:
+		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_49:
+		fx = parent->GetSize(SIZE_XPOS);
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_59:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_69:
+		fx = parent->GetSize(SIZE_XPOS+1);
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_79:
+		fx = parent->GetSize(SIZE_XPOS);
+		fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_89:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_18:	case DH_28:	case DH_38:	case DH_48:
+	case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		fp3d.fx = parent->GetSize(SIZE_XPOS + type - DH_18);
+		fp3d.fy = parent->GetSize(SIZE_YPOS + type - DH_18);
+		fp3d.fz = parent->GetSize(SIZE_ZPOS + type - DH_18);
+		is3D = true;
+		break;
+	default:
+		if(type >= DH_DATA) {
+			fx = parent->GetSize(SIZE_XPOS + type - DH_DATA);
+			fy = parent->GetSize(SIZE_YPOS + type - DH_DATA);
+			FillDef.color = (this == CurrHandle) ? 0x0L : 0x00ffffffL;
+			}
+		else return;
+		}
+	if(is3D) {
+		o->cvec2ivec(&fp3d, &ifp3d);
+		ix = iround(ifp3d.fx);		iy = iround(ifp3d.fy);
+		}
+	else {
+		ix = o->co2ix(fx+dx);	iy = o->co2iy(fy+dy);
+		}
+	SetMinMaxRect(&rDims, ix-4, iy-4, ix+4, iy+4);
+	memcpy(&upd, &rDims, sizeof(RECT));
+	switch(type) {
+	case DH_12:	case DH_22:	case DH_19:	case DH_29:	case DH_39:
+	case DH_49:	case DH_69:	case DH_79:	case DH_89:	case DH_99:
+		o->SetLine(&LineDef);		o->SetFill(&FillDef);
+		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+		o->UpdateRect(&rDims, false);
+		break;
+	case DH_59:
+		o->SetLine(&LineDef);		o->SetFill(&FillDef);
+		IncrementMinMaxRect(&rDims, 2);
+		o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+		IncrementMinMaxRect(&rDims, 1);
+		o->UpdateRect(&rDims, false);
+		break;
+	default:
+		if(type >= DH_DATA) {
+			idx = (type - DH_DATA);
+			o->SetLine(&LineDef);		o->SetFill(&FillDef);
+			if(parent->Id == GO_BEZIER && (idx %3)) {
+				IncrementMinMaxRect(&rDims, -1);
+				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			else if(parent->Id == GO_POLYLINE || parent->Id == GO_BEZIER) {
+				o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			else {
+				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			o->UpdateRect(&rDims, false);
+			}
+		else {
+			IncrementMinMaxRect(&rDims, -1);
+			o->UpdateRect(&rDims, true);
+			}
+		break;
+		}
+}
+
+bool
+dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	lfPOINT pos;
+	int idx;
+
+	if(!parent) return false;
+	switch (cmd) {
+	case CMD_MOUSECURSOR:
+		if(o) switch(type) {
+		case DH_19:	case DH_99:
+			o->MouseCursor(MC_SE, false);							break;
+		case DH_29:	case DH_89:
+			o->MouseCursor(MC_NORTH, false);						break;
+		case DH_39:	case DH_79:
+			o->MouseCursor(MC_NE, false);							break;
+		case DH_49:	case DH_69:
+			o->MouseCursor(MC_EAST, false);							break;
+		default:
+			if(type >= DH_DATA) o->MouseCursor(MC_SALL, false);
+			else o->MouseCursor(MC_MOVE, false);					break;
+			}
+		return true;
+	case CMD_MINRC:
+		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
+		if(tmpl && minRC) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		return true;
+	case CMD_MAXRC:
+		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
+		if(tmpl && maxRC) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		return true;
+	case CMD_MOVE:
+		idx = type >= DH_DATA ? type - DH_DATA : 0;
+		pos.fx = NiceValue(((lfPOINT*)tmpl)[0].fx);
+		pos.fy = NiceValue(((lfPOINT*)tmpl)[0].fy);
+		if(pos.fx == 0.0 && pos.fy == 0.0) return false;
+		parent->Command(CMD_SAVEPOS, &idx, o);
+		switch(type) {
+		case DH_12:
+			parent->SetSize(SIZE_XPOS, pos.fx + parent->GetSize(SIZE_XPOS));
+			parent->SetSize(SIZE_YPOS, pos.fy + parent->GetSize(SIZE_YPOS));
+			break;
+		case DH_22:
+			parent->SetSize(SIZE_XPOS+1, pos.fx + parent->GetSize(SIZE_XPOS+1));
+			parent->SetSize(SIZE_YPOS+1, pos.fy + parent->GetSize(SIZE_YPOS+1));
+			break;
+		case DH_19: parent->parent->SetSize(SIZE_XPOS, 
+						pos.fx + parent->GetSize(SIZE_XPOS));
+		case DH_29: parent->parent->SetSize(SIZE_YPOS,
+						pos.fy + parent->GetSize(SIZE_YPOS));
+			break;
+		case DH_39: parent->parent->SetSize(SIZE_YPOS,
+						pos.fy + parent->GetSize(SIZE_YPOS));
+		case DH_69: parent->parent->SetSize(SIZE_XPOS+1,
+						pos.fx + parent->GetSize(SIZE_XPOS+1));
+			break;
+		case DH_99: parent->parent->SetSize(SIZE_XPOS+1, 
+						pos.fx + parent->GetSize(SIZE_XPOS+1));
+		case DH_89: parent->parent->SetSize(SIZE_YPOS+1,
+						pos.fy + parent->GetSize(SIZE_YPOS+1));
+			break;
+		case DH_79: parent->parent->SetSize(SIZE_YPOS+1,
+						pos.fy + parent->GetSize(SIZE_YPOS+1));
+		case DH_49:
+			parent->parent->SetSize(SIZE_XPOS, 
+						pos.fx + parent->GetSize(SIZE_XPOS));
+			break;
+		case DH_18:	case DH_28:	case DH_38:	case DH_48:
+		case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		case DH_59:
+			return parent->parent->Command(cmd, tmpl, o);
+		default:
+			if (type >= DH_DATA) {
+				parent->SetSize(SIZE_XPOS + idx, pos.fx + parent->GetSize(SIZE_XPOS + idx));
+				parent->SetSize(SIZE_YPOS + idx, pos.fy + parent->GetSize(SIZE_YPOS + idx));
+				CurrGO = parent;
+				}
+			break;
+			}
+		return parent->Command(CMD_REDRAW, 0L, o);
+		break;
+		}
+	return false;
+}
+
+void *
+dragHandle::ObjThere(int x, int y)
+{
+	if(IsInRect(&rDims, x, y)) return (CurrHandle = this);
+	else return 0L;
+}
+
+
+void
+dragHandle::Track(POINT *p, anyOutput *o)
+{
+	POINT p1, p2, pts[5], bez[256];
+	double dx, dy;
+	int i, first=0, last = 0, idx;
+	long nbez;
+	DWORD color;
+
+	if(!parent || !o) return;
+	Command(CMD_MOUSECURSOR, 0L, o);
+	if(upd.right < upd.left) Swap(upd.right, upd.left);
+	if(upd.bottom < upd.top) Swap(upd.bottom, upd.top);
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	IncrementMinMaxRect(&upd, 2);
+	o->UpdateRect(&upd, false);
+	if(type >= DH_19 && type <= DH_99) memcpy(&upd, &drec, sizeof(RECT));
+	color = parent->GetColor(COL_DATA_LINE);
+	switch(type) {
+	case DH_12:
+	case DH_22:
+		pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS)+dx);
+		pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS)+dy);
+		pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx);
+		pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy);
+		if(type == DH_12) {
+			pts[0].x += p->x;			pts[0].y += p->y;
+			}
+		else if(type == DH_22) {
+			pts[1].x += p->x;			pts[1].y += p->y;
+			}
+		UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+		UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+		last = 2;
+		break;
+	case DH_19:
+		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = minRC->left;
+		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+		else upd.left += p->x;
+	case DH_29:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = minRC->top;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = upd.top +p->y >= maxRC->bottom? maxRC->bottom : maxRC->top;
+		else upd.top += p->y;
+		break;
+	case DH_39:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = minRC->top;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = upd.top+p->y >= maxRC->bottom ? maxRC->bottom : maxRC->top;
+		else upd.top += p->y;
+	case DH_69:
+		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = minRC->right;
+		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+		else upd.right += p->x;
+		break;
+	case DH_99:
+		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = minRC->right;
+		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+		else upd.right += p->x;
+	case DH_89:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = minRC->bottom;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+		else upd.bottom += p->y;
+		break;
+	case DH_79:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = minRC->bottom;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+		else upd.bottom += p->y;
+	case DH_49:
+		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = minRC->left;
+		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+		else upd.left += p->x;
+		break;
+	case DH_18:	case DH_28:	case DH_38:	case DH_48:
+	case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		CurrGO = this;
+	case DH_59:
+		parent->parent->Track(p, o);
+		return;
+	default:
+		if(type >= DH_DATA) {
+			idx = type - DH_DATA;
+			pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx)+dx);
+			pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx)+dy);
+			pts[1].x += p->x;				pts[1].y += p->y;
+			if(type > DH_DATA) {
+				pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -1)+dx);
+				pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -1)+dy);
+				}
+			else {
+				pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
+				}
+			pts[3].x = pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
+			pts[3].y = pts[2].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +1)+dy);
+			UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+			UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+			UpdateMinMaxRect(&upd, pts[2].x, pts[2].y);
+			if(parent ->Id == GO_BEZIER) {
+				switch(idx % 3) {
+				case 0:
+					o->ShowLine(pts, 3, 0x00c0c0c0L);
+					pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
+					for(nbez = 0, i = 1; i < 4; i++) {
+						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+						}
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					if(idx < 3) return;
+					pts[3].x = pts[0].x;		pts[3].y = pts[0].y;
+					for(i = nbez = 0, idx -= 3; i < 3; i++) {
+						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+						}
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					return;
+				case 1:		
+					pts[3].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +2)+dx);
+					pts[3].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +2)+dy);
+					last = 2;				break;
+				case 2:	
+					pts[2].x = pts[1].x;	pts[2].y = pts[1].y;
+					pts[1].x = pts[0].x;	pts[1].y = pts[0].y;
+					pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -2)+dx);
+					pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -2)+dy);
+					first = 2;	last = 4;	break;
+					}
+				if(idx %3) {
+					nbez = 0;
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					}
+				color = 0x00c0c0c0L;
+				}
+			else last = 3;
+			if(color == 0x0L || color == 0x00ffffffL) color = 0x00c0c0c0L;
+			}
+		else return;
+		}
+	if(type >= DH_19 && type <= DH_99) {
+		pts[0].x = pts[4].x = pts[3].x = p1.x = upd.left;	
+		pts[0].y = pts[1].y = pts[4].y = p1.y = upd.top;
+		pts[1].x = pts[2].x = p2.x = upd.right;	
+		pts[2].y = pts[3].y = p2.y = upd.bottom;
+		last = 5;
+		if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
+		}
+	o->ShowLine(pts+first, last-first, color);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the dragRect object uses nine dragHandles to create a user interface
+//   for modification of rectangular shapes
+dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
+{
+	int i;
+
+	type = which;
+	Id = GO_DRAGRECT;
+	if(handles = (dragHandle**)calloc(9, sizeof(dragHandle*)))
+		for(i = 0; i < 9; i++){
+			if(i == 4 && type == 0) handles[i] = new dragHandle(this, DH_19 + i);
+			else if(i != 4) handles[i] = new dragHandle(this, DH_19 + i);
+			}
+}
+
+dragRect::~dragRect()
+{
+	int i;
+
+	if(handles) for(i = 0; i < 9; i++) if(handles[i]) DeleteGO(handles[i]);
+}
+
+void
+dragRect::DoPlot(anyOutput *o)
+{
+	int i;
+
+	if(handles) for(i = 0; i < 9; i++) if(handles[i]) handles[i]->DoPlot(o);
+}
+
+bool
+dragRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i;
+
+	if(!parent) return false;
+	switch (cmd) {
+	case CMD_MINRC:
+	case CMD_MAXRC:
+		if(handles) for(i = 0; i < 9; i++) {
+			if(handles[i]) handles[i]->Command(cmd, tmpl, o);
+			}
+		break;
+	case CMD_SAVEPOS:
+	case CMD_REDRAW:
+		return parent->Command(cmd, tmpl, o);
+		}
+	return false;
+}
+
+void *
+dragRect::ObjThere(int x, int y)
+{
+	int i;
+	void *go;
+
+	if(handles)	for(i = 0; i < 9; i++) 
+		if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// implement some kind of virtual trackball for 3D plots
+Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
+{
+	int i;
+
+	Id = GO_DRAG3D;
+	if(handles = (dragHandle**)calloc(8, sizeof(dragHandle*)))
+		for(i = 0; i < 8; i++){
+			handles[i] = new dragHandle(this, DH_18 + i);
+			}
+}
+
+Drag3D::~Drag3D()
+{
+	int i;
+
+	if(handles) for(i = 0; i < 8; i++) if(handles[i]) DeleteGO(handles[i]);
+}
+
+void
+Drag3D::DoPlot(anyOutput *o)
+{
+	int i;
+
+	if(handles) for(i = 0; i < 8; i++) if(handles[i]) handles[i]->DoPlot(o);
+}
+
+void *
+Drag3D::ObjThere(int x, int y)
+{
+	int i;
+	void *go;
+
+	if(handles)	for(i = 0; i < 8; i++) 
+		if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
+	return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// frame rectangle
+FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
+{
+	parent = par;
+	limRC = lim;	cRC = c;	chldRC = chld;
+	drag = 0L;		mo = 0L;
+	Id = GO_FRAMERECT;
+	moveable = true;
+	Fill.type = FILL_NONE;
+	Line.color = FillLine.color = Fill.color = 0x00ffffffL;
+	Line.width = FillLine.width = 0.0;
+	Line.patlength = FillLine.patlength = Fill.scale = 1.0;
+	Line.pattern = FillLine.pattern = 0x0L;
+	Fill.hatch = &FillLine;
+	minRC = maxRC = 0L;
+}
+
+FrmRect::~FrmRect()
+{
+	if(drag) DeleteGO(drag);		drag = 0L;
+	if(minRC) free(minRC);			minRC = 0L;	
+	if(maxRC) free(maxRC);			maxRC = 0L;
+	if(mo) DelBitmapClass(mo);		mo = 0L;
+}
+
+double
+FrmRect::GetSize(int select)
+{
+	switch(select) {
+	case SIZE_XPOS:		return CurrRect.Xmin;
+	case SIZE_XPOS+1:	return CurrRect.Xmax;
+	case SIZE_YPOS:		return CurrRect.Ymin;
+	case SIZE_YPOS+1:	return CurrRect.Ymax;
+		}
+	return 0.0;
+}
+
+bool
+FrmRect::SetSize(int select, double value)
+{
+	double tmp, o_left, o_top;
+
+	o_left = cRC->Xmin;		o_top = cRC->Ymin;
+	switch (select & 0xfff) {
+	case SIZE_XPOS:
+		if(limRC) value -= limRC->Xmin;
+		if(swapX) cRC->Xmax = value;
+		else cRC->Xmin = value;
+		break;
+	case SIZE_XPOS+1:
+		if(limRC) value -= limRC->Xmin;
+		if(swapX) cRC->Xmin = value;
+		else cRC->Xmax = value;
+		break;
+	case SIZE_YPOS:
+		if(limRC) value -= limRC->Ymin;
+		if(swapY) cRC->Ymin = value;
+		else cRC->Ymax = value;
+		break;
+	case SIZE_YPOS+1:
+		if(limRC) value -= limRC->Ymin;
+		if(swapY) cRC->Ymax = value;
+		else cRC->Ymin = value;
+		break;
+	default: return false;
+		}
+	if((swapX && cRC->Xmin < cRC->Xmax) || (!swapX && cRC->Xmin > cRC->Xmax)) {
+		tmp = cRC->Xmin;	cRC->Xmin = cRC->Xmax;	cRC->Xmax = tmp;
+		}
+	if((swapY && cRC->Ymin > cRC->Ymax) || (!swapY && cRC->Ymin < cRC->Ymax)) {
+		tmp = cRC->Ymin;	cRC->Ymin = cRC->Ymax;	cRC->Ymax = tmp;
+		}
+	if(chldRC) {		//check if new rectangle is not inside child rectangle
+		if(cRC->Xmin > o_left+ chldRC->Xmin) cRC->Xmin = o_left + chldRC->Xmin;
+		if(cRC->Xmax < o_left+ chldRC->Xmax) cRC->Xmax = o_left + chldRC->Xmax;
+		if(cRC->Ymin > o_top+ chldRC->Ymin) cRC->Ymin = o_top + chldRC->Ymin;
+		if(cRC->Ymax < o_top+ chldRC->Ymax) cRC->Ymax = o_top + chldRC->Ymax;
+		}
+	if(chldRC && (o_left != cRC->Xmin || o_top != cRC->Ymin)) {
+		chldRC->Xmin -= (tmp = cRC->Xmin - o_left);		chldRC->Xmax -= tmp;
+		chldRC->Ymin -= (tmp = cRC->Ymin - o_top);		chldRC->Ymax -= tmp;
+		}
+	return true;
+}
+
+bool
+FrmRect::SetColor(int select, DWORD col)
+{
+	switch(select & 0xfff){
+	case COL_DRECT:
+		Line.color = col;
+	case COL_BG:
+		Fill.color = col;		return true;
+	case COL_GRECT:
+		Fill.color = col;		return true;
+	case COL_GRECTLINE:
+		Line.color = col;		return true;
+		}
+	return false;
+}
+
+void 
+FrmRect::DoMark(anyOutput *o, bool mark)
+{
+	if(!parent || !o) return;
+	if(!drag && (drag = new dragRect(this, (!limRC && parent->moveable) ? 0 : 1))){
+		if(minRC) drag->Command(CMD_MINRC, minRC, o);
+		if(maxRC) drag->Command(CMD_MAXRC, maxRC, o);
+		}
+	if(mark && drag){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6);
+		mo = GetRectBitmap(&mrc, o);
+		drag->DoPlot(o);
+		o->UpdateRect(&mrc, false);
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+void
+FrmRect::DoPlot(anyOutput *o)
+{
+	int x1, y1, x2, y2;
+	double tmp;
+
+	if(!(cRC) || !o) return;
+	o->dFillCol = Fill.color ^ 0x00ffffff;	//force new brush
+	o->dLineCol = Line.color ^ 0x00ffffff;	//force new pen
+	o->SetLine(&Line);						o->SetFill(&Fill);
+	CurrRect.Xmin = cRC->Xmin;				CurrRect.Xmax = cRC->Xmax;
+	CurrRect.Ymin = cRC->Ymax;				CurrRect.Ymax = cRC->Ymin;
+	if(limRC) {
+		CurrRect.Xmin += limRC->Xmin;		CurrRect.Xmax += limRC->Xmin;
+		CurrRect.Ymin += limRC->Ymin;		CurrRect.Ymax += limRC->Ymin;
+		}
+	if(swapX = (CurrRect.Xmin > CurrRect.Xmax)) {
+		tmp = CurrRect.Xmin;	CurrRect.Xmin = CurrRect.Xmax;	CurrRect.Xmax = tmp;
+		}
+	if(swapY = (CurrRect.Ymin > CurrRect.Ymax)) {
+		tmp = CurrRect.Ymin;	CurrRect.Ymin = CurrRect.Ymax;	CurrRect.Ymax = tmp;
+		}
+	o->oRectangle(x1 = o->co2ix(CurrRect.Xmin), y1 = o->co2iy(CurrRect.Ymin), 
+		x2 = o->co2ix(CurrRect.Xmax), y2 = o->co2iy(CurrRect.Ymax));
+	SetMinMaxRect(&rDims, x1, y1, x2, y2);
+}
+
+bool
+FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	MouseEvent *mev;
+
+	if(!parent) return false;
+	switch (cmd) {
+	case CMD_MOUSE_EVENT:
+		mev = (MouseEvent *) tmpl;
+		switch (mev->Action) {
+		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;
+				return true;
+				}
+			}
+		return false;
+	case CMD_MINRC:
+		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
+		if(minRC && tmpl) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		if(drag) drag->Command(cmd, tmpl, o);
+		return true;
+	case CMD_MAXRC:
+		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
+		if(maxRC && tmpl) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		if(drag) drag->Command(cmd, tmpl, o);
+		return true;
+	case CMD_MOVE:
+		cRC->Xmin += NiceValue(((lfPOINT*)tmpl)[0].fx);
+		cRC->Ymin += NiceValue(((lfPOINT*)tmpl)[0].fy);
+		cRC->Xmax += NiceValue(((lfPOINT*)tmpl)[0].fx);
+		cRC->Ymax += NiceValue(((lfPOINT*)tmpl)[0].fy);
+	case CMD_REDRAW:
+		return parent->Command(CMD_REDRAW, 0L, o);
+	case CMD_SAVEPOS:
+		return parent->Command(cmd, tmpl, o);
+	case CMD_SETCHILD:
+		chldRC = (fRECT*)tmpl;
+		return true;
+		}
+	return false;
+}
+
+void *
+FrmRect::ObjThere(int x, int y)
+{
+	if(drag) return drag->ObjThere(x, y);
+	return 0L;
+}
+
+void
+FrmRect::Track(POINT *p, anyOutput *o)
+{
+	POINT tpts[5];
+	RECT old_rc;
+
+	if(o){
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(cRC->Xmin)+p->x;		
+		tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(cRC->Ymin)+p->y;
+		tpts[1].y = tpts[2].y = o->co2iy(cRC->Ymax)+p->y;
+		tpts[2].x = tpts[3].x = o->co2ix(cRC->Xmax)+p->x;
+		UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
+		UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);	
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		o->ShowLine(tpts, 5, Fill.color ^ 0x00ffffffL);
+		}
+
+}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void * 
+Arrow::ObjThere(int x, int y)
+{
+	if(!IsInRect(&rDims, x, y)) return 0L;
+	if(IsCloseToLine(&pts[0], &pts[1], x, y) ||
+		IsCloseToLine(&pts[2], &pts[3], x, y) ||
+		IsCloseToLine(&pts[3], &pts[4], x, y)){
+		if(dh1 && dh1->ObjThere(x, y)) return dh1;
+		if(dh2 && dh2->ObjThere(x, y)) return dh2;
+		return this;
+		}
+	return 0L;
+}
+
+void
+Arrow::Track(POINT *p, anyOutput *o)
+{
+	POINT *tpts;
+	RECT old_rc;
+	int i;
+
+	if(o && (tpts = (POINT*)malloc(6*sizeof(POINT)))){
+		memcpy(&old_rc, &rDims, sizeof(rDims));
+		o->UpdateRect(&rDims, false);
+		for(i = 0; i < 5; i++) {
+			tpts[i].x = pts[i].x+p->x;
+			tpts[i].y = pts[i].y+p->y;
+			UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+			}
+		switch(type & 0xff) {
+		case ARROW_LINE:
+			o->ShowLine(tpts+2, 3, LineDef.color);
+		case ARROW_NOCAP:
+			o->ShowLine(tpts, 2, LineDef.color);
+			break;
+		case ARROW_TRIANGLE:
+			tpts[5].x = tpts[2].x;		tpts[5].y = tpts[2].y;
+			o->ShowLine(tpts+2, 4, LineDef.color);
+			tpts[1].x = (tpts[2].x + tpts[4].x)>>1;
+			tpts[1].y = (tpts[2].y + tpts[4].y)>>1;
+			o->ShowLine(tpts, 2, LineDef.color);
+			break;
+			}
+		if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+			rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+		free(tpts);
+		}
+}
+
+void
+Label::ShowCursor(anyOutput *o)
+{
+	CalcRect(o);
+	ShowTextCursor(o, &Cursor, TextDef.ColTxt);
+}
+
+bool
+Label::AddChar(int ci, anyOutput *o)
+{
+	char c, *txt1 = 0L;
+	int i, j, k;
+	GraphObj *golist[2];
+
+	if(!o) return false;
+	if(ci == 13 && parent){		//CR
+		if(parent->Id == GO_MLABEL){
+			parent->Command(CMD_SETFOCUS, this, o);
+			return parent->Command(CMD_ADDCHAR, &ci, o);
+			}
+		if(golist[1] = new mLabel(parent, data, fPos.fx, fPos.fy, &TextDef, 
+			TextDef.text, CursorPos, flags)){
+			golist[1]->moveable = moveable;
+			golist[1]->SetSize(SIZE_LB_XDIST, fDist.fx);
+			golist[1]->SetSize(SIZE_LB_YDIST, fDist.fy);
+			}
+		golist[0] = this;
+		if(!parent->Command(CMD_MUTATE, golist, o)) DeleteGO(golist[1]);
+		return false;
+		}
+	if(ci < 254 && 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);
+		}
+	if(TextDef.text) txt1 = (char*)calloc((i = strlen(TextDef.text))+2, sizeof(char));
+	else txt1 = (char*)calloc((i = 0)+2, sizeof(char));
+	if(txt1) {
+		for(j = k = 0; j< i && j < CursorPos; txt1[k++] = TextDef.text[j++]);
+		txt1[k++] = c;
+		for(; j< i; txt1[k++] = TextDef.text[j++]);
+		if(TextDef.text) free(TextDef.text);
+		TextDef.text = txt1;
+		CursorPos++;		RedrawEdit(o);
+		}
+	return true;
+}
+
+void
+Label::CalcCursorPos(int x, int y, anyOutput *o)
+{
+	int i, j, ix, x1, y1, x2, h;
+
+	if(!o || !TextDef.text) return;
+	TextDef.iSize = o->un2iy(TextDef.fSize);
+	if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
+	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);
+		if(x1 <= ix && x2 >= ix) {
+			if((ix-x1) < (x2-ix)) CursorPos = i-1;
+			else CursorPos = i;
+			return;
+			}
+		else if(ix < x2){
+			CursorPos = i-1;
+			return;
+			}
+		x1 = x2;
+		}
+	if(pts[3].x < pts[2].x && x < pts[3].x) CursorPos = 0;
+	else CursorPos = strlen(TextDef.text);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphs are graphic objects containing plots, axes, and drawn objects
+bool
+Graph::ExecTool(MouseEvent *mev)
+{
+	static POINT pl = {0, 0}, pc = {0, 0};
+	static DWORD color = 0L;
+	POINT line[5];
+	GraphObj **tmpPlots, *new_go;
+	TextDEF *td;
+	lfPOINT *lfp, lf;
+	int i, j;
+	double x, y;
+
+	if(!mev || !CurrDisp) return false;
+	td = 0L;
+	if(ToolMode & TM_MOVE) switch (mev->Action) {
+		case MOUSE_LBDOWN:
+			pl.x = pc.x = mev->x;				pl.y = pc.y = mev->y;
+			if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp)) return true;
+			CurrDisp->HideMark();			CurrDisp->MouseCursor(MC_MOVE, false);
+			return true;
+		case MOUSE_MOVE:
+			if(TrackGO) {
+				if(TrackGO->Id == GO_DRAGHANDLE && TrackGO->type >= DH_18 &&
+					TrackGO->type <= DH_88) {
+					lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));	
+					lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
+					TrackGO->Track((POINT*)&lf, CurrDisp);
+					}
+				else {
+					pc.x = mev->x-pl.x;				pc.y = mev->y-pl.y;
+					TrackGO->Track(&pc, CurrDisp);
+					}
+				}
+			return true;
+		case MOUSE_LBUP:
+			if(TrackGO) {
+				ToolMode &= ~TM_MOVE;
+				pc.x = mev->x-pl.x;				pc.y = mev->y-pl.y;
+				if(!pc.x && !pc.y){
+					Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
+					return false;
+					}
+				TrackGO->Track(&pc, CurrDisp);
+				lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));	
+				lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
+				TrackGO->Command(CMD_MOVE, &lf, CurrDisp);
+				bModified = true;
+				}
+			Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
+			return true;
+		default:
+			return true;
+		}
+	if(ToolMode == TM_MARK || ToolMode == TM_ZOOMIN) {
+		switch (mev->Action) {
+		case MOUSE_LBDOWN:			//we should not receive that !
+			rc_mrk.left = mev->x;	rc_mrk.top = mev->y;
+			return false;
+		case MOUSE_LBUP:
+			j = (i = rc_mrk.left - mev->x)*i;
+			j += ((i = rc_mrk.top - mev->y)*i);
+			if(j < 20) {						//glitch
+				rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = 0;
+				ToolMode = TM_STANDARD;		CurrDisp->MouseCursor(MC_ARROW, false);
+				return false;
+				}
+			if(ToolMode == TM_ZOOMIN) {
+				rc_mrk.right = mev->x;	rc_mrk.bottom = mev->y;
+				ToolMode = TM_STANDARD;
+				return Command(CMD_ZOOM, (void*) &"+", 0L);
+				}
+		default:
+			ToolMode = TM_STANDARD;
+		case MOUSE_MOVE:
+			if((mev->StateFlags &1) && rc_mrk.left >= 0 && rc_mrk.top >= 0) {
+				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+					CurrDisp->UpdateRect(&rcUpd, false);
+				line[0].x = line[3].x = line[4].x = rc_mrk.left;
+				line[0].y = line[1].y = line[4].y = rc_mrk.top;
+				line[1].x = line[2].x = mev->x;
+				line[2].y = line[3].y = mev->y;
+				CurrDisp->ShowLine(line, 5, 0x00c0c0c0L);
+				rcUpd.left = rcUpd.right = rc_mrk.left;
+				rcUpd.top = rcUpd.bottom = rc_mrk.top;
+				UpdateMinMaxRect(&rcUpd, rc_mrk.right = mev->x, rc_mrk.bottom = mev->y);
+				IncrementMinMaxRect(&rcUpd,2);
+				}
+			return true;
+			}
+		}
+	if(ToolMode == TM_PASTE) {
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			ToolMode = TM_STANDARD;			CurrDisp->MouseCursor(MC_ARROW, false);
+			break;
+			}
+		return true;
+		}
+	if(NumPlots && !Plots[NumPlots-1]) {
+		Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
+		for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
+		NumPlots = j;
+		}
+	else if(!Plots && !(Plots = (GraphObj**)calloc(2, sizeof(GraphObj*))))return false;
+	else if(Plots[NumPlots]){
+		if(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2) * sizeof(GraphObj*), 0L)){
+			Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+			free(Plots);	Plots = tmpPlots;
+			Plots[NumPlots] = Plots[NumPlots+1] = 0L;
+			}
+		else return false;
+		}
+	switch(ToolMode & 0x0f) {
+	case TM_DRAW:
+		switch (mev->Action) {
+		case MOUSE_LBDOWN:
+			CurrGO = 0L;
+			CurrDisp->MrkMode = MRK_NONE;
+			Command(CMD_REDRAW, 0L, CurrDisp);
+			color = defs.Color(COL_POLYLINE);
+			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
+			if(tl_pts) free(tl_pts);
+			tl_nPts = 0;
+			if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
+				AddToPolygon(&tl_nPts, tl_pts, &pc);
+			return true;
+		case MOUSE_LBUP:
+			pl.x = mev->x;				pl.y = mev->y;
+			if(tl_pts) AddToPolygon(&tl_nPts, tl_pts, &pc);
+			// create line object
+			if(tl_pts && tl_nPts >1) {			//DEBUG: check for plausibility
+				if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
+					for(i = 0; i < tl_nPts; i++) {
+						lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x - CurrDisp->VPorg.fx);	
+						lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y - CurrDisp->VPorg.fy);
+						}
+					if(Plots[NumPlots]) i = NumPlots+1;
+					else i = NumPlots;
+//					Undo.SetGO(this, &Plots[i], new polyline(this, data, lfp, (int)tl_nPts), 0L);
+					Undo.SetGO(this, &Plots[i], new Bezier(this, data, lfp, (int)tl_nPts, 0,
+							(CurrDisp->hres/CurrDisp->VPscale+CurrDisp->vres/CurrDisp->VPscale)/2.0), 0L);
+					if(Plots[i]){
+						NumPlots = i+1;
+						Plots[i]->moveable = 1;
+						Plots[i]->DoPlot(CurrDisp);							//init
+						CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
+						bModified = true;
+						}
+					free(lfp);
+					}
+				if(tl_pts) free(tl_pts);	tl_pts = 0L;	tl_nPts = 0;
+				return true;
+				}
+			if(tl_pts) free(tl_pts);	tl_pts = 0L;	tl_nPts = 0;
+			return false;
+		case MOUSE_MOVE:
+			if((mev->StateFlags &1) && tl_pts && tl_nPts < 4095) {
+				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);
+				return true;
+				}
+			break;
+			}
+		break;
+	case TM_POLYLINE:
+	case TM_POLYGON:
+		switch (mev->Action) {
+		case MOUSE_LBDOWN:
+			if(!tl_pts) {
+				CurrGO = 0L;
+				CurrDisp->MrkMode = MRK_NONE;
+				Command(CMD_REDRAW, 0L, CurrDisp);
+				color = defs.Color((ToolMode & 0x0f) == TM_POLYLINE ? COL_POLYLINE : COL_POLYGON);
+				pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
+				tl_nPts = 0;
+				if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
+				AddToPolygon(&tl_nPts, tl_pts, &pc);
+				rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+				rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+				}
+			return true;
+		case MOUSE_MOVE:
+			if(tl_pts && tl_nPts) {
+				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+					CurrDisp->UpdateRect(&rcUpd, false);
+				CurrDisp->ShowLine(tl_pts, tl_nPts, color);
+				line[1].x = mev->x;				line[1].y = mev->y;
+				line[0].x = pc.x;				line[0].y = pc.y;
+				CurrDisp->ShowLine(line, 2, color);
+				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+				memcpy(&rcUpd, &rcDim, sizeof(RECT));
+				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+				IncrementMinMaxRect(&rcUpd, 2);
+				return true;
+				}
+			break;
+		case MOUSE_LBUP:
+			if(tl_pts && tl_nPts) {
+				memcpy(&pl, &pc, sizeof(POINT));
+				pc.x = mev->x;				pc.y = mev->y;
+				UpdateMinMaxRect(&rcDim, mev->x, mev->y);
+				AddToPolygon(&tl_nPts, tl_pts, &pc);
+				}
+			return true;
+		default:			// create line or polygon object
+			if(tl_pts && tl_nPts >0) {			//DEBUG: check for plausibility
+				pc.x = mev->x;				pc.y = mev->y;
+				AddToPolygon(&tl_nPts, tl_pts, &pc);
+				if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
+					for(i = 0; i < tl_nPts; i++) {
+						lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x-CurrDisp->VPorg.fx);	
+						lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y-CurrDisp->VPorg.fy);
+						}
+					if(Plots[NumPlots]) i = NumPlots+1;
+					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;
+						Plots[i]->moveable = 1;
+						Plots[i]->DoPlot(CurrDisp);							//init
+						CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
+						bModified = true;
+						}
+					free(lfp);
+					}
+				free(tl_pts);			tl_pts = 0L;		tl_nPts = 0;
+				return true;
+				}
+			}
+		if(mev->x == pc.x && mev->y == pc.y) return true;	//rebounce
+		break;
+	case TM_RECTANGLE:	case TM_ELLIPSE:	case TM_ROUNDREC:	case TM_ARROW:
+		switch (mev->Action) {
+		case MOUSE_LBDOWN:
+			CurrGO = 0L;
+			CurrDisp->MrkMode = MRK_NONE;
+			Command(CMD_REDRAW, 0L, CurrDisp);
+			color = defs.Color((ToolMode & 0x0f) != TM_ARROW ? COL_POLYGON : COL_DATA_LINE);
+			pl.x = pc.x = mev->x;		pl.y = pc.y = mev->y;
+			rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+			rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+			return true;
+		case MOUSE_MOVE:
+			if(mev->StateFlags &1) {
+				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+					CurrDisp->UpdateRect(&rcUpd, false);
+				line[0].x = line[4].x = pl.x;	line[0].y = line[4].y = pl.y;
+				if((ToolMode & 0x0f)==TM_ARROW) {
+					line[1].x = pc.x = mev->x;		line[1].y = pc.y = mev->y;
+					CurrDisp->ShowLine(line, 2, color);
+					}
+				else {
+					line[1].x = pc.x = mev->x;		line[1].y = pl.y;
+					line[2].x = mev->x;				line[2].y = pc.y = mev->y;
+					line[3].x = pl.x;				line[3].y = mev->y;
+					CurrDisp->ShowLine(line, 5, color);
+					if((ToolMode & 0x0f) == TM_ELLIPSE) 
+						CurrDisp->ShowEllipse(pc, pl, color);
+					}
+				memcpy(&rcUpd, &rcDim, sizeof(RECT));
+				UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+				IncrementMinMaxRect(&rcUpd, 2);
+				return true;
+				}
+			break;
+		case MOUSE_LBUP:
+			pc.x = mev->x;			pc.y = mev->y;
+			if(((ToolMode & 0x0f)==TM_ARROW || (abs(pc.x-pl.x) >5 && abs(pc.y-pl.y) >5)) && 
+				(lfp = (lfPOINT*)malloc(2 * sizeof(lfPOINT)))){
+				lfp[0].fx = CurrDisp->fix2un(pl.x - CurrDisp->VPorg.fx);
+				lfp[0].fy = CurrDisp->fiy2un(pl.y - CurrDisp->VPorg.fy);
+				lfp[1].fx = CurrDisp->fix2un(pc.x - CurrDisp->VPorg.fx);
+				lfp[1].fy = CurrDisp->fiy2un(pc.y - CurrDisp->VPorg.fy);
+				if(Plots[NumPlots]) i = NumPlots+1;
+				else i = NumPlots;
+				if(ToolMode == TM_RECTANGLE) new_go = new rectangle(this, data,
+					&lfp[0], &lfp[1]);
+				else if(ToolMode == TM_ELLIPSE) new_go = new ellipse(this, data,
+					&lfp[0], &lfp[1]);
+				else if(ToolMode == TM_ROUNDREC) new_go = new roundrec(this, data,
+					&lfp[0], &lfp[1]);
+				else if(ToolMode == TM_ARROW) new_go = new Arrow(this, data,
+					lfp[0], lfp[1], ARROW_UNITS | ARROW_LINE);
+				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
+					Plots[i]->moveable = 1;
+					bModified = true;
+					}
+				free(lfp);
+				}
+			else if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom) {
+				CurrDisp->UpdateRect(&rcUpd, false);
+				}
+			}
+		break;
+	case TM_TEXT:
+		if(Plots[NumPlots]) i = NumPlots+1;
+		else i = NumPlots;
+		switch(mev->Action) {
+		case MOUSE_LBUP:
+			if(!(td = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
+			x = CurrDisp->fix2un(mev->x-CurrDisp->VPorg.fx);
+			y = CurrDisp->fiy2un(mev->y-CurrDisp->VPorg.fy);
+			td->ColTxt = defs.Color(COL_TEXT);		td->ColBg = defs.Color(COL_BG);
+			td->RotBL = td->RotCHAR = 0.0f;			td->fSize = defs.GetSize(SIZE_TEXT);
+			td->Align = TXA_VTOP | TXA_HLEFT;		td->Style = TXS_NORMAL;
+			td->Mode = TXM_TRANSPARENT;				td->Font = FONT_HELVETICA;
+			td->text = 0L;
+			CurrGO = 0L;
+			CurrDisp->MrkMode = MRK_NONE;
+			Command(CMD_REDRAW, 0L, CurrDisp);
+			y -= td->fSize/2.0;
+			Undo.SetGO(this, &Plots[i], new Label(this, data, x, y, td, 0L), 0L);
+			if(Plots[i]){
+				NumPlots = i+1;
+				Plots[i]->DoPlot(CurrDisp);							//init
+				CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW);	//edit
+				Plots[i]->moveable = 1;
+				}
+			free(td);
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+bool
+Graph::MoveObj(int cmd, GraphObj *g)
+{
+	int i, j;
+	GraphObj *g1 = 0;
+
+	if(!g || NumPlots <2 || g->parent != this) return false;
+	switch(cmd) {
+	case CMD_MOVE_TOP:
+		for(i = j = 0; i <NumPlots; i++){
+			if(g == Plots[i]) g1 = Plots[i];
+			else Plots[j++] = Plots[i];
+			}
+		if(g1) {
+			Plots[j++] = g1;
+			return true;
+			}
+		break;
+	case CMD_MOVE_UP:
+		for(i = 0; i<NumPlots-1; i++){
+			if(g == Plots[i]){
+				g1 = Plots[i];	Plots[i] = Plots[i+1];	Plots[i+1] = g1;
+				return true;
+				}
+			}
+		break;
+	case CMD_MOVE_DOWN:
+		for(i = 1; i<NumPlots; i++){
+			if(g == Plots[i]){
+				g1 = Plots[i];	Plots[i] = Plots[i-1];	Plots[i-1] = g1;
+				return true;
+				}
+			}
+		break;
+	case CMD_MOVE_BOTTOM:
+		if(Plots[0] == g) return false;
+		for(i =  j = NumPlots-1; i >= 0; i--) {
+			if(g == Plots[i]) g1 = Plots[i];
+			else Plots[j--] = Plots[i];
+			}
+		if(g1) {
+			Plots[j--] = g1;
+			return true;
+			}
+		break;
+		}
+	return false;
+}
+
+bool
+Graph::DoZoom(char *z)
+{
+	RECT cw;
+	double fac, f1, f2;
+	ZoomDEF *tz;
+	Graph *cg;
+
+	if(!z) return false;
+	if(0==strcmp("fit", z)) {
+		if(CurrGraph) cg = CurrGraph;
+		else cg = this;
+		rc_mrk.left = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_LEFT))-4;
+		rc_mrk.right = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_RIGHT))+4
+			+ iround(CurrDisp->MenuHeight);
+		rc_mrk.top = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_TOP))-4 
+			- iround(CurrDisp->MenuHeight);
+		rc_mrk.bottom = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_BOTTOM))+4;
+		CurrDisp->ActualSize(&cw);
+		f1 = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
+		f2 = ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
+		fac = f1 < f2 ? f1 : f2;
+		if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
+		if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
+		if(fac == 1.0) return false;
+		if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
+			if(zoom_def) free(zoom_def);
+			zoom_def = tz;
+			zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
+			zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
+			zoom_def[zoom_level].scale = CurrDisp->VPscale;
+			zoom_level++;
+			}
+		CurrDisp->VPscale *= fac;
+		if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05; 
+		if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0; 
+		CurrDisp->VPorg.fx = -rc_mrk.left * fac;
+		CurrDisp->VPorg.fy = -rc_mrk.top * fac;
+		HideTextCursor();
+		Command(CMD_SETSCROLL, 0L, CurrDisp);
+		return true;
+		}
+	else if(0==strcmp("+", z)) {
+		if(rc_mrk.left >= 0 && rc_mrk.right >= 0 && rc_mrk.top >= 0 && rc_mrk.bottom >= 0) {
+			if(rc_mrk.left > rc_mrk.right) Swap(rc_mrk.left, rc_mrk.right);
+			if(rc_mrk.top > rc_mrk.bottom) Swap(rc_mrk.top, rc_mrk.bottom);
+			if(5 > (rc_mrk.right - rc_mrk.left) || 5 > (rc_mrk.bottom - rc_mrk.top)) {
+				rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
+				ToolMode = TM_STANDARD;		Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
+				return false;
+				}
+			CurrDisp->ActualSize(&cw);
+			fac = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
+			fac += ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
+			fac /= 2.0;
+			if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
+			if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
+			if(fac == 1.0) return false;
+			if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
+				if(zoom_def) free(zoom_def);
+				zoom_def = tz;
+				zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
+				zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
+				zoom_def[zoom_level].scale = CurrDisp->VPscale;
+				zoom_level++;
+				}
+			CurrDisp->VPscale *= fac;
+			if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05; 
+			if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0; 
+			CurrDisp->VPorg.fx = CurrDisp->VPorg.fx * fac - rc_mrk.left * fac;
+			CurrDisp->VPorg.fy = CurrDisp->VPorg.fy * fac - rc_mrk.top * fac;
+			HideTextCursor();
+			Command(CMD_SETSCROLL, 0L, CurrDisp);
+			CurrDisp->MouseCursor(MC_ARROW, false);
+			rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
+			ToolMode = TM_STANDARD;		Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
+			return true;
+			}
+		else {
+			ToolMode = TM_ZOOMIN;			CurrDisp->MouseCursor(MC_ZOOM, true);
+			}
+		}
+	else if(0==strcmp("-", z)) {
+		HideTextCursor();
+		if(zoom_def && zoom_level > 0) {
+			zoom_level--;
+			if(CurrDisp->VPscale == zoom_def[zoom_level].scale &&
+				CurrDisp->VPorg.fx == zoom_def[zoom_level].org.fx &&
+				CurrDisp->VPorg.fy == zoom_def[zoom_level].org.fy) {
+				DoZoom(z);
+				}
+			else {
+				CurrDisp->VPscale = zoom_def[zoom_level].scale;
+				CurrDisp->VPorg.fx = zoom_def[zoom_level].org.fx;
+				CurrDisp->VPorg.fy = zoom_def[zoom_level].org.fy;
+				}
+			}
+		else {
+			CurrDisp->VPorg.fx = CurrDisp->VPorg.fy = 0.0;
+			CurrDisp->VPscale = Id == GO_PAGE ? 0.5 : 1.0;
+			}
+		Command(CMD_SETSCROLL, 0L, CurrDisp);
+		return true;
+		}
+	else if(0==strcmp("25", z)){
+		CurrDisp->VPscale = 0.25;		return DoZoom("org");
+		}
+	else if(0==strcmp("50", z)){
+		CurrDisp->VPscale = 0.50;		return DoZoom("org");
+		}
+	else if(0==strcmp("100", z)){
+		CurrDisp->VPscale = 1.00;		return DoZoom("org");
+		}
+	else if(0==strcmp("200", z)){
+		CurrDisp->VPscale = 2.00;		return DoZoom("org");
+		}
+	else if(0==strcmp("400", z)){
+		CurrDisp->VPscale = 4.00;		return DoZoom("org");
+		}
+	else if(0==strcmp("org", z)){
+		CurrDisp->VPorg.fx = 0.0;		CurrDisp->VPorg.fy = iround(CurrDisp->MenuHeight);
+		HideTextCursor();
+		Command(CMD_SETSCROLL, 0L, CurrDisp);
+		return DoZoom("reset");
+		}
+	else if(0==strcmp("reset", z)){
+		if(zoom_def && zoom_level > 0) free(zoom_def);
+		zoom_def = 0L;			zoom_level = 0;
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a tree structure of all interesting objects
+//   This object is used e.g. for layer control
+ObjTree::ObjTree(GraphObj *par, DataObj *d, GraphObj *root):GraphObj(par, d)
+{
+	Id = GO_OBJTREE;					base = root;		list=0L;
+	TextDef.ColTxt = 0x00000000L;		TextDef.ColBg = 0x00ffffffL;
+	TextDef.fSize = 4.0;				TextDef.RotBL = TextDef.RotCHAR = 0.0;
+	TextDef.iSize = 0;					TextDef.Align = TXA_HLEFT | TXA_VTOP;
+	TextDef.Mode = TXM_TRANSPARENT;		TextDef.Style = TXS_NORMAL;
+	TextDef.Font = FONT_HELVETICA;		TextDef.text = 0L;
+	Command(CMD_LAYERS, 0L, 0L);
+}
+
+ObjTree::~ObjTree()
+{
+	if(list) free(list);		list = 0L;
+}
+
+void
+ObjTree::DoPlot(anyOutput *o)
+{
+	int i, n, ix, iy;
+	GraphObj *curr_obj;
+
+	if(!o || !list) return;
+	o->Erase(0x00ffffffL);
+	ix = 10;	iy = 0;
+	for(i = 0; i < count; i++, iy += (TextDef.iSize+_SBINC)) {
+		if(list[i]) {
+			curr_obj = list[i];			n = 0;
+			if(i) while(curr_obj && curr_obj != list[0]) {
+				if(curr_obj != list[0]) n += sprintf(TmpTxt + n, " -");
+				if(curr_obj) curr_obj = curr_obj->parent; 
+				}
+			sprintf(TmpTxt + n, "%s%s", n ? " " : "", get_name(i));
+			if(list[i]->Id >= GO_PLOT && list[i]->Id < GO_GRAPH) {
+				TextDef.ColTxt = ((Plot*)list[i])->hidden ? 0x00000080L : 0x00008000L;
+				}
+			else TextDef.ColTxt = 0x00000000L;
+			o->SetTextSpec(&TextDef);
+			o->oTextOut(ix, iy, TmpTxt, 0);
+			}
+		}
+}
+
+bool
+ObjTree::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	switch(cmd){
+	case CMD_LAYERS:
+		if(list) free(list);
+		count = 0;		maxcount = 100;
+		if(base) {
+			if(list = (GraphObj**) malloc(100 * sizeof(GraphObj*))) {
+				list[count++] = base;
+				}
+			base->Command(CMD_OBJTREE, this, 0L);
+			}
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_OBJTREE;
+		return true;
+	case CMD_UPDATE:
+		if(tmpl && (((GraphObj*)tmpl)->Id >= GO_PLOT && ((GraphObj*)tmpl)->Id < GO_SPREADDATA)
+			|| ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+			if(count >= maxcount) {
+				maxcount += 100;
+				list = (GraphObj**) realloc(list, maxcount);
+				}
+			if(list) list[count++] = (GraphObj*)tmpl;
+			}
+		return true;
+	case CMD_TEXTDEF:
+		if(tmpl) memcpy(&TextDef, tmpl, sizeof(TextDEF));
+		TextDef.text = 0L;
+		return true;
+		}
+	return false;
+}
+
+anyOutput *
+ObjTree::CreateBitmap(int *bw, int *bh, anyOutput *tmpl)
+{
+	anyOutput *bmp = 0L;
+	int h;
+	
+	h = tmpl->un2iy(TextDef.fSize) * count;
+	if(h > *bh) *bh = h;
+	if(bmp = NewBitmapClass(*bw, *bh, tmpl->hres, tmpl->vres)) DoPlot(bmp);
+	return bmp;
+}
+
+char *
+ObjTree::get_name(int li)
+{
+	if(li < count && list[li] && list[li]->name) return list[li]->name;
+	else return "(unknown)";
+}
+
+int
+ObjTree::get_vis(int li)
+{
+	if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH)
+		return ((Plot*)list[li])->hidden ? 0 : 1;
+	return 2;
+}
+
+bool
+ObjTree::set_vis(int li, bool vis)
+{
+	if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH) {
+		((Plot*)list[li])->hidden = vis ? 0 : 1;
+		list[li]->Command(CMD_MRK_DIRTY, 0L, 0L);
+		list[li]->Command(CMD_REDRAW, 0L, 0L);
+		}
+	return false;
+}
+
+GraphObj*
+ObjTree::get_obj(int li)
+{
+	if(li < count && list[li]) return list[li];
+	return 0L;
+}
+

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