//PropertyDlg.cpp, Copyright (c) 2001-2008 R.Lackner
//Property dialogs for graphic objects
//
//    This file is part of RLPlot.
//
//    RLPlot is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    RLPlot is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with RLPlot; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
#include "rlplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "TheDialog.h"

extern tag_Units Units[];
extern char TmpTxt[];
extern TextDEF DlgText;
extern Default defs;
extern int dlgtxtheight;
extern Axis **CurrAxes;
extern UndoObj Undo;
extern int AxisTempl3D;

int ODtickstyle;

//prototypes: WinSpec.cpp
void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Symbol properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *SymDlg_DlgTmpl = 
	"1,+,,DEFAULT,PUSHBUTTON,-1,145,10,60,12\n"
	".,.,,,PUSHBUTTON,2,145,25,60,12\n"
	".,.,,,PUSHBUTTON,-2,145,40,60,12\n"
	".,50,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
	".,+,100,TOUCHEXIT | ISPARENT | CHECKED,SHEET,3,5,10,130,113\n"
	".,.,200,TOUCHEXIT | ISPARENT,SHEET,4,5,10,130,113\n"
	".,,300,TOUCHEXIT | ISPARENT,SHEET,5,5,10,130,113\n"
	"50,,,TOUCHEXIT,SYMBUTT,0,155,75,40,40\n"
	"100,+,,,RTEXT,6,5,25,45,8\n"
	".,.,,TOUCHEXIT,INCDECVAL1,9,55,25,32,10\n"
	".,.,,,LTEXT,-3,89,25,20,8\n"
	".,.,,,RTEXT,10,5,37,45,8\n"
	".,.,,TOUCHEXIT,INCDECVAL1,11,55,37,32,10\n"
	".,.,,,LTEXT,-3,89,37,20,8\n"
	".,.,,,RTEXT,12,5,49,45,8\n"
	".,.,,TOUCHEXIT | OWNDIALOG, COLBUTT,13,55,49,25,10\n"
	".,.,,,RTEXT,14,5,61,45,8\n"
	".,401,,TOUCHEXIT | OWNDIALOG,COLBUTT,15,55,61,25,10\n"
	"200,204,201,CHECKED | ISPARENT, GROUPBOX,16,12,28,50,39\n"
	".,+,,TOUCHEXIT, RADIO1,17,15,33,45,8\n"
	".,.,,TOUCHEXIT, RADIO1,18,15,43,45,8\n"
	".,,,TOUCHEXIT, RADIO1,19,15,53,43,8\n"
	".,250,205,CHECKED | ISPARENT, GROUPBOX,20,72,28,57,39\n"
	"205,+,,TOUCHEXIT, CHECKBOX,21,75,33,25,8\n"
	".,.,,TOUCHEXIT, CHECKBOX,22,75,43,25,8\n"
	".,,,TOUCHEXIT, CHECKBOX,23,75,53,25,8\n"
	"250,+,,TOUCHEXIT | CHECKED, RADIO1,24,10,75,45,8\n"
	".,.,,,EDTEXT,25,60,75,68,10\n"
	".,.,,TOUCHEXIT,RADIO1,26,10,92,60,8\n"
	".,,,,RANGEINPUT,27,20,102,100,10\n"
	"300,+,,,RTEXT,-12,5,30,45,8\n"
	".,.,,,EDVAL1,7,55,30,45,10\n"
	".,.,,,RTEXT,-13,5,50,45,8\n"
	".,,,LASTOBJ,EDVAL1,8,55,50,45,10";

bool
Symbol::PropertyDlg()
{
	TabSHEET tab1 = {0, 47, 10, "Size & Color"};
	TabSHEET tab2 = {47, 70, 10, "Text"};
	TabSHEET tab3 = {70, 92, 10, "Edit"};
	Symbol *PrevSym = 0L;
	char text1[40], text2[100];
	void *dyndata[] = {(void*)"Apply to Symbol", (void*)"Apply to PLOT", (void*)&tab1,
		(void*)&tab2, (void*)&tab3, (void*)"size", (void*)&fPos.fx, (void*)&fPos.fy,
		(void*)&size, (void*)"line width", (void*)&SymLine.width, (void*)"line color",
		(void *)&SymLine.color, (void*)"fill color", (void *)&SymFill.color, (void*)" font ",
		(void*)"Helvetica", (void*)"Times", (void*)"Courier", (void*)" style ", (void*)"bold",
		(void*)"italic", (void*)"underlined", (void*)"fixed text:", (void*)text1,
		(void*)"from spreadsheet range:", (void*)text2};
	DlgInfo *SymDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, k, ix, iy, tmpType, res, width, height, n_syms;
	DWORD tmpCol, undo_flags = 0L;
	double tmpVal, o_size, n_size, o_lwidth, n_lwidth;
	TextDEF textdef;
	bool bContinue = false;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT o_pos, n_pos;
	static const int syms[] = {SYM_CIRCLE, SYM_CIRCLEF, SYM_CIRCLEC, SYM_RECT, SYM_RECTF, SYM_RECTC, 
		SYM_TRIAU, SYM_TRIAUF, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR, SYM_TRIAD, SYM_TRIADF, SYM_TRIADC,
		SYM_TRIADL, SYM_TRIADR, SYM_DIAMOND, SYM_DIAMONDF, SYM_DIAMONDC, SYM_5GON, SYM_5GONF, SYM_5GONC,
		SYM_4STAR, SYM_4STARF, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD,
		SYM_3QUAD, SYM_PLUS, SYM_CROSS, SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT};

	if(!(SymDlg = CompileDialog(SymDlg_DlgTmpl, dyndata)))return false;
	if(!Command(CMD_GETTEXT, (void*)text1, 0L)) rlp_strcpy(text1, 40, "text");
#ifdef USE_WIN_SECURE
	if(parent && data && data->GetSize(&width, &height)) sprintf_s(text2, 100, "b1:b%d", height);
#else
	if(parent && data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
#endif
	else rlp_strcpy(text2, 100, "(not available)");
	n_syms = sizeof(syms)/sizeof(int);
	for(k = 1; !(SymDlg[k-1].flags & LASTOBJ); k++);
	if(!parent) n_syms--;
	if(!(SymDlg = (DlgInfo *)realloc(SymDlg, (k+n_syms)*sizeof(DlgInfo)))) return false;
	SymDlg[k-1].flags &= (~LASTOBJ);
	for(i = 1, iy = 66; i <= n_syms; i++, ix += 10) {
		if((i%11) == 1) {
			iy += 10;		ix = 15;
			}
		SymDlg[k].id = 400 + i;					SymDlg[k].next = 400 + i + 1;
		SymDlg[k].first = 0;					SymDlg[k].flags = TOUCHEXIT;
		SymDlg[k].type = SYMRADIO;				SymDlg[k].ptype = (void*)&syms[i-1];
		SymDlg[k].x = ix;						SymDlg[k].y = iy;
		if(type == syms[i-1]) SymDlg[k].flags |= CHECKED;
		SymDlg[k].w = SymDlg[k].h = 10;			k++;
		}
	SymDlg[k-1].flags |= LASTOBJ;				if(parent) SymDlg[k-1].w = 30;
	if(parent) {
		SymDlg[0].ptype = dyndata[0];
		}
	else {
		SymDlg[5].flags |= HIDDEN;				SymDlg[6].flags |= HIDDEN;
		SymDlg[1].flags |= HIDDEN;				SymDlg[2].y = 25;
		SymDlg[0].w = SymDlg[2].w = 45;			SymDlg[7].x = 145;
		}
	if((PrevSym = new Symbol(0L, data, 0.0f, 0.0f, type))){
		PrevSym->SetColor(COL_SYM_LINE, SymLine.color);
		PrevSym->SetColor(COL_SYM_FILL, SymFill.color);
		PrevSym->SetSize(SIZE_SYMBOL, size);
		PrevSym->SetSize(SIZE_SYM_LINE, SymLine.width);
		PrevSym->Command(CMD_SETTEXT, (void*)text1, 0L);
		PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L);
		PrevSym->Command(CMD_SET_DATAOBJ, (void*)data, 0L);
		if(Command(CMD_GETTEXTDEF, &textdef, 0L))
			PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
		PrevSym->idx = idx;
		SymDlg[7].ptype = (void*)&PrevSym;
		}
	if(PrevSym && (Dlg = new DlgRoot(SymDlg, data))) {
		Dlg->TextFont(201, FONT_HELVETICA);
		Dlg->TextFont(202, FONT_TIMES);
		Dlg->TextFont(203, FONT_COURIER);
		Dlg->TextStyle(205, TXS_BOLD);
		Dlg->TextStyle(206, TXS_ITALIC);
		Dlg->TextStyle(207, TXS_UNDERLINE);
		switch(textdef.Font) {
		case FONT_TIMES:	Dlg->SetCheck(202, 0L, true);	break;
		case FONT_COURIER:	Dlg->SetCheck(203, 0L, true);	break;
		default:			Dlg->SetCheck(201, 0L, true);	break;
			}
		if(textdef.Style & TXS_BOLD) Dlg->SetCheck(205, 0L, true);
		if(textdef.Style & TXS_ITALIC) Dlg->SetCheck(206, 0L, true);
		if(textdef.Style & TXS_UNDERLINE) Dlg->SetCheck(207, 0L, true);
		}
	else return false;
	if(parent && parent->name) {
		width = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol of ");
		rlp_strcpy(TmpTxt+width, TMP_TXT_SIZE-width, parent->name);
		width =10;
		}
	else {
		rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol properties");
		}
	if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, parent ? 430 : 400, 292, Dlg, 0x4L)))return false;
	tmpCol = 0x00c0c0c0L;	o_size = size;	o_lwidth = SymLine.width;
	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lwidth);
	n_size = o_size;					n_lwidth = o_lwidth;
	o_pos.fx = fPos.fx;					o_pos.fy = fPos.fy;
	if(Dlg->GetValue(301, &tmpVal)) o_pos.fx = tmpVal;	n_pos.fx = o_pos.fx;
	if(Dlg->GetValue(303, &tmpVal)) o_pos.fy = tmpVal;	n_pos.fy = o_pos.fy;
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res){
		case 0:
			if(bContinue) res = -1;
			break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);
			if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
				Dlg->GetText(251, text1, 40);
				if(PrevSym->Command(CMD_GETTEXT, (void *)text2, 0L) && strcmp(text1, text2)) {
					PrevSym->Command(CMD_SETTEXT, (void *)text1, 0L);
					Dlg->DoPlot(NULL);
					res = -1;
					}
				}
			else if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
				if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
					PrevSym->Command(CMD_RANGETEXT, &text2, 0L);
				}
			Dlg->GetValue(101, &n_size);		Dlg->GetValue(104, &n_lwidth);
			break;
		case 5:		case 7:
			bContinue = false;			res = -1;
		case 6:											//the text sheets
			if(parent)Dlg->SetCheck(400+n_syms, 0L, true);
			if(PrevSym->type != SYM_TEXT) {
				PrevSym->type = SYM_TEXT;		Dlg->DoPlot(0L);
				}
			res = -1;		bContinue = true;
			break;
		case 201:	case 202:	case 203:				//fonts and styles
		case 205:	case 206:	case 207:
			if(PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L)) {
				if(Dlg->GetCheck(202)) textdef.Font = FONT_TIMES;
				else if(Dlg->GetCheck(203)) textdef.Font = FONT_COURIER;
				else textdef.Font = FONT_HELVETICA;
				textdef.Style = TXS_NORMAL;
				if(Dlg->GetCheck(205)) textdef.Style |= TXS_BOLD;
				if(Dlg->GetCheck(206)) textdef.Style |= TXS_ITALIC;
				if(Dlg->GetCheck(207)) textdef.Style |= TXS_UNDERLINE;
				PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
				Dlg->DoPlot(0L);
				}
			res = -1;
			break;
		default:										//symbol selection ?
			if(res > 400 && res <= (400+n_syms)) tmpType = syms[res-401];
			else break;
			PrevSym->type = tmpType;
		case 107:										//line color button
			if(res == 107 && Dlg->GetColor(107, &tmpCol))
				PrevSym->SetColor(COL_SYM_LINE, tmpCol);
		case 109:										//fill color button
			if(res == 109 && Dlg->GetColor(109, &tmpCol)) 
				PrevSym->SetColor(COL_SYM_FILL, tmpCol);
		case 101:										//symbol size changed
		case 104:										//line width changed
		case 50:										//preview button
			if(Dlg->GetValue(101, &tmpVal))	PrevSym->SetSize(SIZE_SYMBOL, tmpVal);
			if(Dlg->GetValue(104, &tmpVal))	PrevSym->SetSize(SIZE_SYM_LINE, tmpVal);
			if(PrevSym->type == SYM_TEXT) {
				if(Dlg->GetCheck(250) && Dlg->GetText(251,text1,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
				else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2,100))	
					PrevSym->Command(CMD_RANGETEXT, text2, 0L);
				}
			Dlg->DoPlot(0L);
			res = -1;
			break;
		case 252:										//use spreadsheet text
			if(!data) Dlg->SetCheck(250, 0L, true);
		case 250:										//use fixed text
			if(Dlg->GetCheck(250) && Dlg->GetText(251,text1,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
				PrevSym->Command(CMD_RANGETEXT, text2, 0L);
			Dlg->DoPlot(NULL);
			res = -1;
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:								//accept values for symbol
		undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
		undo_flags = CheckNewFloat(&SymLine.width, o_lwidth, n_lwidth, parent, undo_flags);
		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
		if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
		if(Dlg->GetColor(107, &tmpCol)) undo_flags = 
			CheckNewDword(&SymLine.color, SymLine.color, tmpCol, parent, undo_flags);
		if(Dlg->GetColor(109, &tmpCol)) undo_flags = 
			CheckNewDword(&SymFill.color, SymFill.color, tmpCol, parent, undo_flags);
		undo_flags = CheckNewInt(&type, type, PrevSym->type, parent, undo_flags);
		if(type == SYM_TEXT && PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L)){
			if(SymTxt && cmpTextDEF(SymTxt, &textdef)){
				Undo.TextDef(parent, SymTxt, undo_flags);	undo_flags |= UNDO_CONTINUE;
				}
			if(PrevSym->Command(CMD_GETTEXT, text1, 0L)) Command(CMD_SETTEXT, text1, 0L);
			Command(CMD_SETTEXTDEF, &textdef, 0L);
			}
		break;
	case 2:								//accept values for all symbols of plot
		parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
		undo_flags |= UNDO_CONTINUE;
		parent->SetSize(SIZE_SYMBOL, n_size);
		parent->SetSize(SIZE_SYM_LINE, n_lwidth);
		if(Dlg->GetColor(107, &tmpCol))	parent->SetColor(COL_SYM_LINE, tmpCol);
		if(Dlg->GetColor(109, &tmpCol))	parent->SetColor(COL_SYM_FILL, tmpCol);
		parent->Command(CMD_SYM_TYPE, (void*)(& PrevSym->type), 0L);
		if(PrevSym->type == SYM_TEXT) {
			if(Dlg->GetCheck(250) && PrevSym->Command(CMD_GETTEXT, text1, 0L))
				parent->Command(CMD_SYMTEXT_UNDO, text1, 0L);
			else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))	
				parent->Command(CMD_SYM_RANGETEXT, text2, 0L);
			if(PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L))
				parent->Command(CMD_SYMTEXTDEF, &textdef, 0L);
			}
		break;
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(SymDlg);
	delete PrevSym;			return undo_flags != 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bubble properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *BubDlg_DlgTmpl = 
	"1,+,,DEFAULT,PUSHBUTTON,1,130,10,60,12\n"
	".,.,,,PUSHBUTTON,2,130,25,60,12\n"
	".,.,,,PUSHBUTTON,-2,130,40,60,12\n"
	".,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
	"5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,100\n"
	".,.,200,ISPARENT,SHEET,4,5,10,120,100\n"
	".,,300,ISPARENT,SHEET,5,5,10,120,100\n"
	"100,109,,NOSELECT,ODBUTTON,6,18,57,90,50\n"
	"109,+,,ISRADIO,ODBUTTON,7,30,30,20,20\n"
	".,.,,ISRADIO,ODBUTTON,7,50,30,20,20\n"
	".,.,,ISRADIO,ODBUTTON,7,70,30,20,20\n"
	".,,,ISRADIO,ODBUTTON,7,90,30,20,20\n"
	"200,+,,,LTEXT,8,10,30,110,8\n"
	".,.,210,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,,,LTEXT,9,10,64,110,8\n"
	".,,220,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"210,+,,,RADIO1,-3,40,38,45,8\n"
	".,.,,,RADIO1,10,40,46,45,8\n"
	".,,,,RADIO1,11,40,54,45,8\n"
	"220,+,,,RADIO1,12,40,72,45,8\n"
	".,.,,,RADIO1,13,40,80,45,8\n"
	".,,,,RADIO1,14,40,88,45,8\n"
	"300,+,,,RTEXT,-12,10,40,45,8\n"
	".,.,,,EDVAL1,15,60,40,35,10\n"
	".,.,,,RTEXT,-13,10,60,45,8\n"
	".,.,,,EDVAL1,16,60,60,35,10\n"
	".,.,,,RTEXT,17,10,80,45,8\n"
	".,,,LASTOBJ,EDVAL1,18,60,80,35,10";

bool
Bubble::PropertyDlg()
{
	TabSHEET tab1 = {0, 52, 10, "Shape & Color"};
	TabSHEET tab2 = {52, 84, 10, "Scaling"};
	TabSHEET tab3 = {84, 106, 10, "Edit"};
	int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
	void *dyndata[] = {(void*)"Apply to BUBBLE", (void*)"Apply to PLOT", (void*)&tab1, (void*)&tab2,
		(void*)&tab3, (void*)&OD_filldef, (void *)OD_BubbleTempl, (void*)"sizes are given as",
		(void*)"proportionality (relative to circle)", (void*)"scaling with X axis",
		(void*)"scaling with Y axis", (void*)"diameter", (void*)"circumference", (void*)"area", (void*)&fPos.fx,
		(void*)&fPos.fy, (void*)"size", (void*)&fs};
	DlgInfo *BubDlg = CompileDialog(BubDlg_DlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType;
	lfPOINT o_pos, n_pos;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	double o_size, n_size;
	bool bRet = false;

	if(!parent) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BubbleLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BubbleFill, 0);
	Dlg = new DlgRoot(BubDlg, data);
	switch(type & 0x00f) {
	case BUBBLE_SQUARE:		Dlg->SetCheck(110, 0L, true);		break;
	case BUBBLE_UPTRIA:		Dlg->SetCheck(111, 0L, true);		break;
	case BUBBLE_DOWNTRIA:	Dlg->SetCheck(112, 0L, true);		break;
	default:				Dlg->SetCheck(109, 0L, true);		break;
		}
	switch(type & 0x0f0) {
	case BUBBLE_XAXIS:		Dlg->SetCheck(211, 0L, true);		break;
	case BUBBLE_YAXIS:		Dlg->SetCheck(212, 0L, true);		break;
	default:				Dlg->SetCheck(210, 0L, true);		break;
		}
	switch(type & 0xf00) {
	case BUBBLE_CIRCUM:		Dlg->SetCheck(221, 0L, true);		break;
	case BUBBLE_AREA:		Dlg->SetCheck(222, 0L, true);		break;
	default:				Dlg->SetCheck(220, 0L, true);		break;
		}
	if(!Dlg->GetValue(301, &o_pos.fx))	o_pos.fx = fPos.fx;
	if(!Dlg->GetValue(303, &o_pos.fy))	o_pos.fy = fPos.fy;
	if(!Dlg->GetValue(305, &o_size))	o_size = fs;
	n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;	n_size = o_size;
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble Properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 396, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 1:			//accept for current bubble only
		case 2:			//accept for plot
			Undo.SetDisp(cdisp);
			OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
			memcpy(&newFillLine, &BubbleFillLine, sizeof(LineDEF));
			if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
			if(Dlg->GetCheck(110)) tmpType = BUBBLE_SQUARE;
			else if(Dlg->GetCheck(111)) tmpType = BUBBLE_UPTRIA;
			else if(Dlg->GetCheck(112)) tmpType = BUBBLE_DOWNTRIA;
			else tmpType = BUBBLE_CIRCLE;
			if(Dlg->GetCheck(211)) tmpType |= BUBBLE_XAXIS;
			else if(Dlg->GetCheck(212)) tmpType |= BUBBLE_YAXIS;
			if(Dlg->GetCheck(221)) tmpType |= BUBBLE_CIRCUM;
			else if(Dlg->GetCheck(222)) tmpType |= BUBBLE_AREA;
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:				//new setting for current bubble only
		Dlg->GetValue(301, &n_pos.fx);		Dlg->GetValue(303, &n_pos.fy);
		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		Dlg->GetValue(305, &n_size);
		undo_flags = CheckNewFloat(&fs, o_size, n_size, parent, undo_flags);
		if(cmpLineDEF(&BubbleLine, &newLine)) {
			Undo.Line(parent, &BubbleLine, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&BubbleLine, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&BubbleFillLine, &newFillLine)) {
			Undo.Line(parent, &BubbleFillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&BubbleFillLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&BubbleFill, &newFill)) {
			Undo.Fill(parent, &BubbleFill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&BubbleFill, &newFill, sizeof(FillDEF));
			}
		BubbleFill.hatch = &BubbleFillLine;
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		break;
	case 2:				//accept settings for plot
		parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
		parent->Command(CMD_BUBBLE_TYPE, (void*)(& tmpType), 0L);
		parent->Command(CMD_BUBBLE_ATTRIB, (void*)(& tmpType), 0L);
		parent->Command(CMD_BUBBLE_FILL, (void*)&newFill, 0L);
		parent->Command(CMD_BUBBLE_LINE, (void*)&newLine, 0L);
		bRet = true;
		break;
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(BubDlg);		return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bar properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *BarDlg_DlgTmpl = 
	"1,+,,DEFAULT,PUSHBUTTON,1,130,10,55,12\n"
	".,.,,,PUSHBUTTON,2,130,25,55,12\n"
	".,.,,,PUSHBUTTON,-2,130,40,55,12\n"
	".,,5,CHECKED | ISPARENT,GROUP,0,138,40,55,12\n"
	"5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,120\n"
	".,.,200,ISPARENT,SHEET,4,5,10,120,120\n"
	".,,300,ISPARENT,SHEET,5,5,10,120,120\n"
	"100,109,,NOSELECT,ODBUTTON,6,18,30,90,50\n"
	"109,+,,,LTEXT,7,10,80,45,8\n"
	".,.,,,RADIO1,8,20,92,25,8\n"
	".,.,,,EDTEXT,9,60,92,25,10\n"
	".,.,,,LTEXT,-3,87,92,20,8\n"
	".,.,,,RADIO1,10,20,104,25,8\n"
	".,.,,,EDTEXT,11,60,104,25,10\n"
	".,,,,LTEXT,-10,87,104,10,8\n"
	"200,+,,TOUCHEXIT,RADIO2,12,20,30,45,8\n"
	".,205,202,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
	".,+,,TOUCHEXIT,RADIO1,13,30,40,35,8\n"
	".,.,,TOUCHEXIT,RADIO1,14,30,48,35,8\n"
	".,,,TOUCHEXIT,RADIO1,15,30,56,35,8\n"
	"205,+,,,EDVAL1,16,65,56,35,10\n"
	".,.,,TOUCHEXIT,RADIO2,17,20,70,45,8\n"
	".,211,208,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
	"208,+,,TOUCHEXIT,RADIO1,18,30,80,35,8\n"
	".,.,,TOUCHEXIT,RADIO1,19,30,88,35,8\n"
	".,,,TOUCHEXIT,RADIO1,20,30,96,35,8\n"
	"211,+,,,EDVAL1,21,65,96,35,10\n"
	".,,,,CHECKBOX,22,20,113,50,8\n"
	"300,+,,,RTEXT,-12,10,50,45,8\n"
	".,.,,,EDVAL1,23,60,50,40,10\n"
	".,.,,,RTEXT,-13,10,75,45,8\n"
	".,,,LASTOBJ,EDVAL1,24,60,75,40,10";
bool
Bar::PropertyDlg()
{
	TabSHEET tab1 = {0, 50, 10, "Size & Color"};
	TabSHEET tab2 = {50, 90, 10, "Baseline"};
	TabSHEET tab3 = {90, 120, 10, "Edit"};
	char sTxt1[20], sTxt2[20];
	void *dyndata[] = {(void*)"Apply to BAR", (void*)"Apply to PLOT", (void*)&tab1,
		(void*)&tab2, (void*)&tab3, (void*)OD_filldef, (void*)"bar width:", (void*)" fixed",
		(void*)&sTxt1[1], (void*)" relative", (void*)&sTxt2[1], (void*)"vertical bars",
		(void*)"bottom baseline", (void*)"top", (void*)"user y =", (void*)&BarBase.fy,
		(void*)"horizontal bars", (void*)"left baseline", (void*)"right", (void*)"user x =",
		(void*)&BarBase.fx, (void*)"bars centered across baseline", (void*)&fPos.fx, (void*)&fPos.fy};
	DlgInfo *BarDlg = CompileDialog(BarDlg_DlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	double n_size;
	int cb, res, tmpType = type;
	bool bRet = false;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT o_bl, n_bl, o_pos, n_pos;

	if(!parent) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
	if(type & BAR_RELWIDTH) {
		WriteNatFloatToBuff(sTxt2, size);
		WriteNatFloatToBuff(sTxt1, DefSize(SIZE_BAR));
		}
	else {
		WriteNatFloatToBuff(sTxt1, size);
		rlp_strcpy(sTxt2, 20, " 50");
		}
	Dlg = new DlgRoot(BarDlg, data);
	switch (type & 0xff) {
	case BAR_VERTB:		case BAR_VERTT:		case BAR_VERTU:
		Dlg->SetCheck(200, 0L, true);
		Dlg->SetCheck(208, 0L, true);
		switch(type & 0xff) {
		case BAR_VERTT:	Dlg->SetCheck(203, 0L, true);	break;
		case BAR_VERTU:	Dlg->SetCheck(204, 0L, true);	break;
		default:		Dlg->SetCheck(202, 0L, true);	break;
			}
		break;
	case BAR_HORL:		case BAR_HORR:		case BAR_HORU:
		Dlg->SetCheck(206, 0L, true);
		Dlg->SetCheck(202, 0L, true);
		switch(type & 0xff) {
		case BAR_HORR:	Dlg->SetCheck(209, 0L, true);	break;
		case BAR_HORU:	Dlg->SetCheck(210, 0L, true);	break;
		default:		Dlg->SetCheck(208, 0L, true);	break;
			}
		break;
		}
	if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
	else Dlg->SetCheck(110, 0L, true);
	if(type & BAR_CENTERED) Dlg->SetCheck(212, 0L, true);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar properties");
	if(!Dlg->GetValue(211, &o_bl.fx))	o_bl.fx = BarBase.fx;
	if(!Dlg->GetValue(205, &o_bl.fy))	o_bl.fy = BarBase.fy;
	if(!Dlg->GetValue(301, &o_pos.fx))	o_pos.fx = fPos.fx;
	if(!Dlg->GetValue(303, &o_pos.fy))	o_pos.fy = fPos.fy;
	n_bl.fx = o_bl.fx;			n_bl.fy = o_bl.fy;
	n_pos.fx = o_pos.fx;		n_pos.fy = o_pos.fy;
	n_size = size;
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 300, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 202:	case 203:	case 204:
			Dlg->SetCheck(200, NULL, true);
			tmpType = res == 202 ? BAR_VERTB : res == 203 ? BAR_VERTT : BAR_VERTU;
			res = -1;				//continue on radiobutton
			break;
		case 208:	case 209:	case 210:
			Dlg->SetCheck(206, NULL, true);
			tmpType = res == 208 ? BAR_HORL : res == 209 ? BAR_HORR : BAR_HORU;
			res = -1;				//continue on radiobutton
			break;
		case 200:					//group of vertical bars
			if(Dlg->GetCheck(203)) tmpType = BAR_VERTT;
			else if(Dlg->GetCheck(204)) tmpType = BAR_VERTU;
			else tmpType = BAR_VERTB;
			res = -1;
			break;
		case 206:					//group of horizontal bars
			if(Dlg->GetCheck(209)) tmpType = BAR_HORR;
			else if(Dlg->GetCheck(210)) tmpType = BAR_HORU;
			else tmpType = BAR_HORL;
			res = -1;
			break;
		case 1:
		case 2:
			Undo.SetDisp(cdisp);
			OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
			memcpy(&newFillLine, &HatchLine, sizeof(LineDEF));
			if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
			if(Dlg->GetCheck(113)) {
				tmpType |= BAR_RELWIDTH;			Dlg->GetValue(114, &n_size);
				}
			else {
				tmpType &= ~BAR_RELWIDTH;			Dlg->GetValue(111, &n_size);
				}
			if(Dlg->GetCheck(212))tmpType |= BAR_CENTERED; 
			else tmpType &= ~BAR_CENTERED;
			Dlg->GetValue(211, &n_bl.fx);			Dlg->GetValue(205, &n_bl.fy);
			Dlg->GetValue(301, &n_pos.fx);			Dlg->GetValue(303, &n_pos.fy);
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:				//new setting for current bar only
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		undo_flags = CheckNewLFPoint(&BarBase, &o_bl, &n_bl, parent, undo_flags);
		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
		undo_flags = CheckNewFloat(&size, size, n_size, parent, undo_flags);
		if(cmpLineDEF(&BarLine, &newLine)) {
			Undo.Line(parent, &BarLine, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&BarLine, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&HatchLine, &newFillLine)) {
			Undo.Line(parent, &HatchLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&HatchLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&BarFill, &newFill)) {
			Undo.Fill(parent, &BarFill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&BarFill, &newFill, sizeof(FillDEF));
			}
		BarFill.hatch = &HatchLine;
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		break;
	case 2:				//new settings to all bars of plot
		parent->Command(CMD_SAVE_BARS, 0L, 0L);
		if(parent->Id == GO_PLOTSCATT && parent->parent 
			&& parent->parent->Id == GO_STACKBAR){ 
			parent->parent->SetSize(SIZE_BAR, n_size);
			parent->parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
			}
		else {
			parent->SetSize(SIZE_BAR, n_size);
			parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
			}
		parent->SetColor(COL_BAR_LINE, newLine.color);
		parent->SetSize(SIZE_BAR_LINE, newLine.width);
		parent->SetSize(SIZE_YBASE, n_bl.fy);
		parent->SetSize(SIZE_XBASE, n_bl.fx);
		parent->Command(CMD_MRK_DIRTY, 0L, 0L);
		parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
		parent->Command(CMD_BAR_FILL, (void *)&newFill, 0L);
		bRet = true;
		break;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(BarDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Data line properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *LineDlg_DlgTmpl =
	"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
	"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,139,120\n"
	"5,6,200,ISPARENT,SHEET,2,5,10,139,120\n"
	"6,,300,ISPARENT | HIDDEN,SHEET,3,5,10,139,120\n"
	"100,,,NOSELECT,ODBUTTON,9,10,38,130,100\n"
	"200,201,,,LTEXT,-27,10,32,130,100\n"
	"201,202,,EXRADIO,ODBUTTON,10,12,45,25,25\n"
	"202,203,,EXRADIO,ODBUTTON,10,37,45,25,25\n"
	"203,204,,EXRADIO,ODBUTTON,10,62,45,25,25\n"
	"204,205,,EXRADIO,ODBUTTON,10,87,45,25,25\n"
	"205,206,,EXRADIO,ODBUTTON,10,112,45,25,25\n"
	"206,207,,EXRADIO,ODBUTTON,10,37,70,25,25\n"
	"207,208,,EXRADIO,ODBUTTON,10,62,70,25,25\n"
	"208,209,,EXRADIO,ODBUTTON,10,87,70,25,25\n"
	"209,210,,EXRADIO,ODBUTTON,10,112,70,25,25\n"
	"210,211,,EXRADIO,ODBUTTON,10,37,95,25,25\n"
	"211,212,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
	"212,,,EXRADIO,ODBUTTON,10,87,95,25,25\n"
	"300,301,,,LTEXT,5,15,30,80,9\n"
	"301,302,,,EDTEXT,7,15,40,119,10\n"
	"302,303,,,LTEXT,6,15,55,80,9\n"
	"303,,,LASTOBJ,EDTEXT,8,15,65,119,10";

bool
DataLine::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Line"};
	TabSHEET tab2 = {40, 80, 10, "Style"};
	TabSHEET tab3 = {80, 120, 10, "Edit"};
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)0L, 
		(void*)"range for x-values", (void*)"range for y-values", (void*)ssXref, (void*)ssYref,
		(void*)OD_linedef, (void*)(OD_LineStyleTempl)};
	DlgInfo *LineDlg = CompileDialog(LineDlg_DlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType = type;
	DWORD undo_flags = 0L;
	LineDEF newLine;
	bool bRet = false;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(parent->Id == GO_FUNCTION) return parent->PropertyDlg();
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
	Dlg->SetCheck(201 + (type & 0x0f), 0L, true);
	if(ssXref && ssYref) Dlg->ShowItem(6, true);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 201:	case 202:	case 203:	case 204:	case 205:	case 206:
		case 207:	case 208:	case 209:	case 210:	case 211:	case 212:
			if((tmpType & 0x0f) == (res-201)) res = 1;
			else {
				tmpType &= ~0x0f;	tmpType |= (res-201);
				res = -1;
				}
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		Undo.SetDisp(cdisp);
		if(ssXref && ssYref) {
			TmpTxt[0] = 0;		Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE); 
			undo_flags = CheckNewString(&ssXref, ssXref, TmpTxt, this, undo_flags);
			TmpTxt[0] = 0;	Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE);
			undo_flags = CheckNewString(&ssYref, ssYref, TmpTxt, this, undo_flags);
			if(undo_flags & UNDO_CONTINUE) {
				Command(CMD_UPDATE, 0L, cdisp);			parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
				}
			}
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(parent, &LineDef, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			}
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;		free(LineDlg);		return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Data polygon properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *PolygonDlg_DlgTmpl =
	"1,2,,DEFAULT,PUSHBUTTON,-1,120,10,45,12\n"
	"2,3,,,PUSHBUTTON,-2,120,25,45,12\n"
	"3,,4,CHECKED,GROUP,0,0,0,0,0\n"
	"4,5,100,ISPARENT | CHECKED, SHEET,1, 5,10,110,75\n"
	"5,,200,ISPARENT,SHEET,2,5,10,110,75\n"
	"100,,,NOSELECT,ODBUTTON,3,23,30,90,50\n"
	"200,201,,,LTEXT,-27,10,32,130,100\n"
	"201,202,,EXRADIO,ODBUTTON,4,10,45,25,25\n"
	"202,203,,EXRADIO,ODBUTTON,4,35,45,25,25\n"
	"203,213,,EXRADIO,ODBUTTON,4,60,45,25,25\n"
	"213,,,LASTOBJ | EXRADIO,ODBUTTON,4,85,45,25,25";
bool
DataPolygon::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Polygon"};
	TabSHEET tab2 = {40, 70, 10, "Style"};
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)OD_filldef, (void*)OD_PolygonStyleTempl};
	DlgInfo *PolygonDlg;
	DlgRoot *Dlg;
	void *hDlg;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	int cb, res, tmpType = type;
	bool bRet = false;

	if(!data || !parent) return false;
	if(!(PolygonDlg = CompileDialog(PolygonDlg_DlgTmpl, dyndata))) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
	Dlg = new DlgRoot(PolygonDlg, data);
	switch (type & 0x0f) {
		case 0:		default:
			Dlg->SetCheck(201, 0L, true);
			break;
		case 1:		case 2:		case 12:
			Dlg->SetCheck(201+type, 0L, true);
			break;
		}
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else if(parent->Id == GO_TICK) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Isopleth \"");
		if(parent->Command(CMD_GETTEXT, TmpTxt+cb, 0L)) {
			cb = (int)strlen(TmpTxt); TmpTxt[cb++] = '"';	TmpTxt[cb++] = ' ';
			}
		else cb--;
		cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE, "Properties");
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon Properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 348, 210, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 201:	case 202:	case 203:	case 213:
			if((tmpType & 0x0f) == (res-201)) res = 1;
			else {
				tmpType &= ~0x0f;	tmpType |= (res-201);
				res = -1;
				}
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		Undo.SetDisp(cdisp);
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
		memcpy(&newFillLine, &pgFillLine, sizeof(LineDEF));
		if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(parent, &LineDef, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&pgFillLine, &newFillLine)) {
			Undo.Line(parent, &pgFillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&pgFillLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&pgFill, &newFill)) {
			Undo.Fill(parent, &pgFill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&pgFill, &newFill, sizeof(FillDEF));
			}
		pgFill.hatch = &pgFillLine;
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;	free(PolygonDlg);	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Regression line properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
RegLine::PropertyDlg()
{
	TabSHEET tab1 = {0, 30, 10, "Line"};
	TabSHEET tab2 = {30, 60, 10, "Model"};
	TabSHEET tab3 = {60, 95, 10, "Clipping"};
	char text1[60], text2[60], text3[60], text4[60], text5[60];
	DlgInfo LineDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 144, 130},
		{5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 144, 130},
		{6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 144, 130},
		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 12, 38, 130, 100},
		{200, 201, 0, TOUCHEXIT, RADIO1, (void*)"y dependent on x", 15, 25, 130, 8},
		{201, 202, 0, 0x0L, LTEXT, (void*)text1, 25, 33, 120, 8},
		{202, 203, 0, TOUCHEXIT, RADIO1, (void*)"x dependent on y", 15, 45, 130, 8},
		{203, 204, 0, 0x0L, LTEXT, (void*)text2, 25, 53, 120, 8},
		{204, 205, 0, TOUCHEXIT, RADIO1, (void*)"mixed model", 15, 65, 130, 8},
		{205, 206, 0, 0x0L, LTEXT, (void*)text3, 25, 73, 120, 8},
		{206, 207, 0, TOUCHEXIT, RADIO1, (void*)"zero crossing (x = 0, y = 0)", 15, 85, 130, 8},
		{207, 208, 0, 0x0L, LTEXT, (void*)text4, 25, 93, 120, 8},
		{208, 209, 0, TOUCHEXIT, RADIO1, (void*)"set manually", 15, 105, 130, 8},
		{209, 210, 0, 0x0L, LTEXT, (void*)text5, 25, 113, 60, 8},
		{210, 211, 0, 0x0L, RTEXT, (void*)"a =", 92, 113, 10, 8},
		{211, 212, 0, 0x0L, EDVAL1, &l5.fx, 104, 113, 40, 10},
		{212, 213, 0, 0x0L, RTEXT, (void*)"b =", 92, 125, 10, 8},
		{213, 0, 0, 0x0L, EDVAL1, &l5.fy, 104, 125, 40, 10},
		{300, 301, 0, 0x0L, LTEXT, (void*)"Line length is limited by", 15, 30, 100, 8},
		{301, 302, 0, TOUCHEXIT, RADIO1, (void*)"data minima and maxima", 15, 45, 100, 8},
		{302, 303, 0, TOUCHEXIT, RADIO1, (void*)"frame rectangle", 15, 60, 100, 8},
		{303, 304, 0, TOUCHEXIT, RADIO1, (void*)"user defined values", 15, 75, 100, 8},
		{304, 305, 0, 0x0L, RTEXT, (void*)"x", 10, 89, 15, 8},
		{305, 306, 0, 0x0L, EDVAL1, &uclip.Xmin, 27, 89, 40, 10},
		{306, 307, 0, 0x0L, LTEXT, (void*)"-", 70, 89, 5, 8},
		{307, 308, 0, 0x0L, EDVAL1, &uclip.Xmax, 76, 89, 40, 10},
		{308, 309, 0, 0x0L, LTEXT, (void*)"[data]", 119, 89, 15, 8},
		{309, 310, 0, 0x0L, RTEXT, (void*)"y", 10, 101, 15, 8},
		{310, 311, 0, 0x0L, EDVAL1, &uclip.Ymin, 27, 101, 40, 10},
		{311, 312, 0, 0x0L, LTEXT, (void*)"-", 70, 101, 5, 8},
		{312, 313, 0, 0x0L, EDVAL1, &uclip.Ymax, 76, 101, 40, 10},
		{313, 0, 0, LASTOBJ, LTEXT, (void*)"[data]", 119, 101, 15, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType;
	bool bRet = false;
	LineDEF newLine;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT o_l5, n_l5;
	fRECT o_clip, n_clip;
	char *tx, *ty;

	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	switch(type &0x700) {
	case 0x100:		tx = "log(x)";	break;
	case 0x200:		tx = "(1/x)";	break;
	case 0x300:		tx = "sqrt(x)"; break;
	default:		tx = "x";		break;
		}
	switch(type &0x7000) {
	case 0x1000:	ty = "log(y)";	break;
	case 0x2000:	ty = "(1/y)";	break;
	case 0x3000:	ty = "sqrt(y)"; break;
	default:		ty = "y";		break;
		}
#ifdef USE_WIN_SECURE
	sprintf_s(text1, 60, "%s = %.3lf + %.3lf * %s   (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
	sprintf_s(text2, 60, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
	sprintf_s(text3, 60, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
	sprintf_s(text4, 60, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
	sprintf_s(text5, 60, "%s = a + b * %s", ty, tx);
#else
	sprintf(text1, "%s = %.3lf + %.3lf * %s   (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
	sprintf(text2, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
	sprintf(text3, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
	sprintf(text4, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
	sprintf(text5, "%s = a + b * %s", ty, tx);
#endif
	if(!(Dlg = new DlgRoot(LineDlg, data))) return false;
	Dlg->Activate(211, false);	Dlg->Activate(213, false);
	switch(type & 0x07) {
	case 1:		Dlg->SetCheck(202, 0L, true);	break;
	case 2:		Dlg->SetCheck(204, 0L, true);	break;
	case 3:		Dlg->SetCheck(206, 0L, true);	break;
	case 4:		
		Dlg->SetCheck(208, 0L, true);
		Dlg->Activate(211, true);	Dlg->Activate(213, true);
		break;
	default:	Dlg->SetCheck(200, 0L, true);	break;
		}
	switch(type & 0x70) {
	case 0x10:	Dlg->SetCheck(302, 0L, true);	break;
	case 0x20:	Dlg->SetCheck(303, 0L, true);	break;
	default:	Dlg->SetCheck(301, 0L, true);	break;
		}
	if(0x20 == (type & 0x70)) {
		Dlg->Activate(305, true);	Dlg->Activate(307, true);
		Dlg->Activate(310, true);	Dlg->Activate(312, true);
		}
	else {
		Dlg->Activate(305, false);	Dlg->Activate(307, false);
		Dlg->Activate(310, false);	Dlg->Activate(312, false);
		}
	if(!Dlg->GetValue(211, &o_l5.fx))	o_l5.fx = l5.fx;
	if(!Dlg->GetValue(213, &o_l5.fy))	o_l5.fy = l5.fy;
	n_l5.fx = o_l5.fx;			n_l5.fy = o_l5.fy;
	if(!Dlg->GetValue(305, &o_clip.Xmin)) o_clip.Xmin = uclip.Xmin;
	if(!Dlg->GetValue(307, &o_clip.Xmax)) o_clip.Xmax = uclip.Xmax;
	if(!Dlg->GetValue(310, &o_clip.Ymin)) o_clip.Ymin = uclip.Ymin;
	if(!Dlg->GetValue(312, &o_clip.Ymax)) o_clip.Ymax = uclip.Ymax;
	memcpy(&n_clip, &o_clip, sizeof(fRECT));
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line properties");
	hDlg = CreateDlgWnd(cp ? TmpTxt : 
		(char*)"Linear regression analysis step 2/2", 50, 50, 420, 320, Dlg, 0x4L);
	if(!cp) Dlg->SetCheck(5, 0L, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 200:	case 202:	case 204:	case 206:
			Dlg->Activate(211, false);	Dlg->Activate(213, false);
			res = -1;
			break;
		case 208:
			Dlg->Activate(211, true);	Dlg->Activate(213, true);
			res = -1;
			break;
		case 301:	case 302:
			Dlg->Activate(305, false);	Dlg->Activate(307, false);
			Dlg->Activate(310, false);	Dlg->Activate(312, false);
			res = -1;
			break;
		case 303:
			Dlg->Activate(305, true);	Dlg->Activate(307, true);
			Dlg->Activate(310, true);	Dlg->Activate(312, true);
			res = -1;
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		Undo.SetDisp(cdisp);
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(parent, &LineDef, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			}
		tmpType = type & (~0x77);
		if(Dlg->GetCheck(202)) tmpType |= 1;
		else if(Dlg->GetCheck(204)) tmpType |= 2;
		else if(Dlg->GetCheck(206)) tmpType |= 3;
		else if(Dlg->GetCheck(208)) tmpType |= 4;
		if(Dlg->GetCheck(302)) tmpType |= 0x10;
		else if(Dlg->GetCheck(303)) tmpType |= 0x20;
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		Dlg->GetValue(211, &n_l5.fx);			Dlg->GetValue(213, &n_l5.fy);
		undo_flags = CheckNewLFPoint(&l5, &o_l5, &n_l5, parent, undo_flags);
		Dlg->GetValue(305, &n_clip.Xmin);		Dlg->GetValue(307, &n_clip.Xmax);
		Dlg->GetValue(310, &n_clip.Ymin);		Dlg->GetValue(312, &n_clip.Ymax);
		undo_flags = CheckNewFloat(&uclip.Xmin, o_clip.Xmin, n_clip.Xmin, parent, undo_flags);
		undo_flags = CheckNewFloat(&uclip.Xmax, o_clip.Xmax, n_clip.Xmax, parent, undo_flags);
		undo_flags = CheckNewFloat(&uclip.Ymin, o_clip.Ymin, n_clip.Ymin, parent, undo_flags);
		undo_flags = CheckNewFloat(&uclip.Ymax, o_clip.Ymax, n_clip.Ymax, parent, undo_flags);
		if(!cp || (undo_flags & UNDO_CONTINUE)) bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SDellipse properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char* SdEllipseDlg_Tmpl = 
	"1,+,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
	".,.,,,PUSHBUTTON,-2,150,25,45,12\n"
	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,139,140\n"
	".,,200,ISPARENT,SHEET,2,5,10,139,140\n"
	"100,,,NOSELECT,ODBUTTON,3,10,48,130,100\n"
	"200,+,,,CHECKBOX,4,20,26,80,9\n"
	".,.,250,CHECKED, GROUPBOX,5,10,45,129,100\n"
	"250,+,,,LTEXT,6,25,82,60,8\n"
	".,.,,,RTEXT,7,20,92,60,8\n"
	".,.,,,LTEXT,0,82,92,30,8\n"
	".,.,,,RTEXT,8,20,100,60,8\n"
	".,.,,,LTEXT,0,82,100,30,8\n"
	".,.,,,LTEXT,9,25,112,60,8\n"
	".,.,,,RTEXT,10,20,122,60,8\n"
	".,.,,,LTEXT,0,82,122,30,8\n"
	".,.,,,RTEXT,11,20,130,60,8\n"
	".,.,,,LTEXT,0,82,130,30,8\n"
	".,.,,,LTEXT,12,25,52,30,8\n"
	".,.,,,RADIO1,13,50,52,30,8\n"
	".,.,,,RADIO1,14,50,61,30,8\n"
	".,,,LASTOBJ,RADIO1,15,50,70,30,8";
bool
SDellipse::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Line"};
	TabSHEET tab2 = {40, 80, 10, "Details"};
	void *dyndata[] = {(void*)&tab1, (void*) &tab2, (void*)OD_linedef, (void*)" show regression line",
		(void*)"  ellipse  ", (void*)"center (means of data)", (void*)"x =", (void*)"y =",
		(void*)"standard deviation (S.D.)", (void*)"major axis", (void*)"minor axis", (void*)"size:",
		(void*)" 1 x S.D.", (void*)" 2 x S.D.", (void*)" 3 x S.D."};
	DlgInfo *ellDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType;
	LineDEF newLine;
	bool bRet = false;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(!(ellDlg = CompileDialog(SdEllipseDlg_Tmpl, dyndata))) return false;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	if(!(Dlg = new DlgRoot(ellDlg, data))) return false;
	if(!(type & 0x10000)) Dlg->SetCheck(200, 0L, true);
	WriteNatFloatToBuff(TmpTxt, mx);		Dlg->SetText(252, TmpTxt+1);
	WriteNatFloatToBuff(TmpTxt, my);		Dlg->SetText(254, TmpTxt+1);
	rlp_strcpy(TmpTxt, 4, "+/-");
	WriteNatFloatToBuff(TmpTxt+3, sd1);		Dlg->SetText(259, TmpTxt);
	WriteNatFloatToBuff(TmpTxt+3, sd2);		Dlg->SetText(257, TmpTxt);
	switch(type & 0x60000) {
		case 0x20000:	Dlg->SetCheck(262, 0L, true);	break;
		case 0x40000:	Dlg->SetCheck(263, 0L, true);	break;
		default:		Dlg->SetCheck(261, 0L, true);	break;
		}
	tmpType = type;
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 340, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		}while (res < 0);
	if(res == 1){						//OK pressed
		Undo.SetDisp(cdisp);
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(parent, &LineDef, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			}
		if(Dlg->GetCheck(200)) tmpType &= ~0x10000;
		else tmpType |= 0x10000;
		tmpType &= ~0x60000;
		if(Dlg->GetCheck(262)) tmpType |= 0x20000;
		else if(Dlg->GetCheck(263)) tmpType |= 0x40000;
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(ellDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Normal error bars properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
ErrorBar::PropertyDlg()
{
	TabSHEET tab1 = {0, 38, 10, "Error Bar"};
	TabSHEET tab2 = {38, 65, 10, "Type"};
	TabSHEET tab3 = {65, 90, 10, "Edit"};
	DlgInfo ErrDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to ERROR", 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, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
		{100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
		{101, 102, 0, 0x0L, EDVAL1, &SizeBar, 46, 40, 25, 10},
		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
		{103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 55, 28, 8},
		{104, 105, 0, 0x0L, EDVAL1, &ErrLine.width, 46, 55, 25, 10},
		{105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 55, 20, 8},
		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
		{107, 0, 0, OWNDIALOG, COLBUTT, (void *)&ErrLine.color, 46, 70, 25, 10},
		{200, 0, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 15, 30, 28, 8},
		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 30, 35, 10},
		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 45, 28, 8},
		{303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 45, 35, 10},
		{304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 60, 28, 8},
		{305, 306, 0, 0x0L, EDVAL1, &ferr, 46, 60, 35, 10},
		{306, 307, 0, 0x0L, LTEXT, (void*)"description:", 10, 80, 70, 8},
		{307, 0, 0, 0x0L, EDTEXT, (void*)name, 10, 90, 80, 10},
		{500, 501, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 12, 40, 25, 25},
		{501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 37, 40, 25, 25},
		{502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 40, 25, 25},
		{503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 12, 65, 25, 25},
		{504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 37, 65, 25, 25},
		{505, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 65, 25, 25}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType = type;
	double n_sb, o_sb, n_lw, o_lw, n_err, o_err;
	lfPOINT n_pos, o_pos;
	DWORD n_col, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	bool bRet = false;
	char desc[80];

	if(!parent) return false;
	desc[0] = 0;
	if(!(Dlg = new DlgRoot(ErrDlg, data)))return false;
	Dlg->SetCheck(500 + (type & 0x7), 0L, true);
	if(!(Dlg->GetValue(101, &o_sb))) o_sb = SizeBar;
	if(!(Dlg->GetValue(104, &o_lw))) o_lw = ErrLine.width;
	if(!(Dlg->GetValue(305, &o_err))) o_err = ferr;
	if(!(Dlg->GetValue(301, &o_pos.fx))) o_pos.fx = fPos.fx;
	if(!(Dlg->GetValue(303, &o_pos.fy))) o_pos.fy = fPos.fy;
	n_sb = o_sb;	n_lw = o_lw;	n_err = o_err; n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 500:	case 501:	case 502:
		case 503:	case 504:	case 505:
			tmpType = res-500;			res = -1;	break;
		case 7:								//edit tab
			Dlg->Activate(307, true);	res = -1;	break;
		case 1:								//accept for this object
		case 2:								//   or all objects of plot
			desc[0] = 0;
			Undo.SetDisp(cdisp);			Dlg->GetText(307, desc, 80);
			Dlg->GetValue(101, &n_sb);		Dlg->GetValue(104, &n_lw);
			Dlg->GetColor(107, &n_col);		Dlg->GetValue(305, &n_err);
			Dlg->GetValue(301, &n_pos.fx);	Dlg->GetValue(303, &n_pos.fy);
			break;
			}
		}while (res <0);
	switch (res) {
	case 1:				//new setting for current error bar only
		undo_flags = CheckNewFloat(&ferr, o_err, n_err, parent, undo_flags);
		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
		undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
		undo_flags = CheckNewFloat(&SizeBar, o_sb, n_sb, parent, undo_flags);
		undo_flags = CheckNewFloat(&ErrLine.width, o_lw, n_lw, parent, undo_flags);
		undo_flags = CheckNewDword(&ErrLine.color, ErrLine.color, n_col, parent, undo_flags);
		undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		break;
	case 2:				//new settings to all error bars of plot
		parent->Command(CMD_SAVE_ERRS, 0L, 0L);
		if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 0L);
		parent->SetSize(SIZE_ERRBAR, n_sb);
		parent->SetSize(SIZE_ERRBAR_LINE, n_lw);
		parent->SetColor(COL_ERROR_LINE, n_col);
		if(type != tmpType) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
		bRet = parent->Command(CMD_ERR_TYPE, (void*)(& tmpType), 0L);
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Arrow properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Arrow::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, type & ARROW_UNITS ? 
			(void*)"OK" : (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, 
			type & ARROW_UNITS ? 25 : 40, 57, 12},
		{4, 50, 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},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{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, &LineDef.width, 46, 70, 25, 10},
		{108, 109, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 70, 20, 8},
		{109, 110, 0, 0x0L, RTEXT, (void*)"color", 15, 82, 28, 8},
		{110, 0, 0, OWNDIALOG, COLBUTT, (void *)&LineDef.color, 46, 82, 25, 10},
		{200, 201, 0, TOUCHEXIT, RADIO1, (void*)"line only", 15, 40, 60, 8},
		{201, 202, 0, TOUCHEXIT, RADIO1, (void*)"arrow with lines", 15, 55, 60, 8},
		{202, 0, 0, TOUCHEXIT, RADIO1, (void*)"filled arrow", 15, 70, 60, 8},
		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 30, 28, 8},
		{301, 302, 0, 0x0L, EDVAL1, &pos2.fx, 46, 30, 35, 10},
		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 42, 28, 8},
		{303, 304, 0, 0x0L, EDVAL1, &pos2.fy, 46, 42, 35, 10},
		{304, 305, 0, 0x0L, RTEXT, (void*)"origin x", 10, 60, 28, 8},
		{305, 306, 0, 0x0L, EDVAL1, &pos1.fx, 46, 60, 35, 10},
		{306, 307, 0, 0x0L, RTEXT, (void*)" y", 10, 72, 28, 8},
		{307, 308, 0, 0x0L, EDVAL1, &pos1.fy, 46, 72, 35, 10},
		{308, 309, 0, 0x0L, CHECKBOX, (void*)"set common origin to", 16, 85, 70, 8},
		{309, 0, 0, 0x0L, LTEXT, (void*)"all arrows of plot", 25, 93, 65, 8},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 108, 67, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 134, 67, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 134, 82, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 108, 82, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	lfPOINT o_pos1, o_pos2, n_pos1, n_pos2;
	double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
	int cb, res, tmptype = type, undo_level = *Undo.pcb;
	bool bRet = false;
	DWORD o_col, n_col, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(!(Dlg = new DlgRoot(ArrowDlg, data))) return false;
	Dlg->GetValue(301, &o_pos2.fx);		Dlg->GetValue(303, &o_pos2.fy);
	Dlg->GetValue(305, &o_pos1.fx);		Dlg->GetValue(307, &o_pos1.fy);
	Dlg->GetValue(101, &o_cw);			Dlg->GetValue(104, &o_cl);
	Dlg->GetValue(107, &o_lw);			Dlg->GetColor(110, &o_col);
	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	switch(type & 0xff) {
	case ARROW_LINE:		Dlg->SetCheck(201, 0L, true);		break;
	case ARROW_TRIANGLE:	Dlg->SetCheck(202, 0L, true);		break;
	default:				Dlg->SetCheck(200, 0L, true);		break;
		}
	if(tmptype & ARROW_UNITS){
		Dlg->ShowItem(2, false);
		Dlg->ShowItem(308, false);		Dlg->ShowItem(309, false);
		}
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();			res = Dlg->GetResult();
		switch (res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);
			}
		switch (res) {
		case 200:	tmptype = ARROW_NOCAP;		res = -1;	break;
		case 201:	tmptype = ARROW_LINE;		res = -1;	break;
		case 202:	tmptype = ARROW_TRIANGLE;	res = -1;	break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);
			Dlg->GetValue(301, &n_pos2.fx);		Dlg->GetValue(303, &n_pos2.fy);
			Dlg->GetValue(305, &n_pos1.fx);		Dlg->GetValue(307, &n_pos1.fy);
			Dlg->GetValue(101, &n_cw);			Dlg->GetValue(104, &n_cl);
			Dlg->GetValue(107, &n_lw);			Dlg->GetColor(110, &n_col);
			break;
			}
		}while (res <0);
	switch (res) {
	case 1:				//new setting for current arrow
		if(n_pos1.fx != o_pos1.fx || n_pos1.fy != o_pos1.fy ||
			n_pos2.fx != o_pos2.fx || n_pos2.fy != o_pos2.fy){
			Command(CMD_SAVEPOS, 0L, 0L);				undo_flags |= UNDO_CONTINUE;
			memcpy(&pos1, &n_pos1, sizeof(lfPOINT));	memcpy(&pos2, &n_pos2, sizeof(lfPOINT));
			if(!(type & ARROW_UNITS)) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			}
		if((type & 0xff) != (tmptype & 0xff)){
			Undo.ValInt(this, &type, undo_flags);
			type &= ~0xff;	type |= (tmptype & 0xff);	undo_flags |= UNDO_CONTINUE;
			}
		undo_flags = CheckNewFloat(&cw, o_cw, n_cw, this, undo_flags);
		undo_flags = CheckNewFloat(&cl, o_cl, n_cl, this, undo_flags);
		undo_flags = CheckNewFloat(&LineDef.width, o_lw, n_lw, this, undo_flags);
		undo_flags = CheckNewDword(&LineDef.color, o_col, n_col, this, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bModified = true;
		bRet = true;
		break;
	case 2:				//new settings to all arrows of plot
		if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
			parent->Command(CMD_SAVE_ARROWS, 0L, 0L);
			if(Dlg->GetCheck(308)) parent->Command(CMD_ARROW_ORG, &n_pos1, 0L);
			parent->SetSize(SIZE_ARROW_LINE, n_lw);
			parent->SetSize(SIZE_ARROW_CAPWIDTH, n_cw);
			parent->SetSize(SIZE_ARROW_CAPLENGTH, n_cl);
			parent->SetColor(COL_ARROW, n_col);
			parent->Command(CMD_ARROW_TYPE, &tmptype, 0L);
			bRet = true;
			}
		break;
	case 3:								//Cancel
		Undo.SetDisp(cdisp);
		if(*Undo.pcb > undo_level) {	//restore plot order
			while(*Undo.pcb > undo_level)	Undo.Restore(false, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Box properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Box::PropertyDlg()
{
	TabSHEET tab1 = {0, 50, 10, "Size & Color"};
	TabSHEET tab2 = {50, 90, 10, "Edit"};
	char sTxt1[20], sTxt2[20];
	DlgInfo BoxDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BOX", 130, 10, 55, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 55, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 55, 12},
		{4, 0, 5, CHECKED | ISPARENT, GROUP, 0L, 138, 40, 55, 12},
		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 115},
		{6, 0, 300, ISPARENT, SHEET, &tab2, 5, 10, 120, 115},
		{100, 105, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
		{105, 0, 109, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0},
		{109, 110, 0, 0x0L, LTEXT, (void*)"bar width:", 10, 80, 45, 8},
		{110, 111, 0, 0x0L, RADIO1, (void*)" fixed", 20, 92, 25, 8},
		{111, 112, 0, 0x0L, EDTEXT, &sTxt1[1], 60, 92, 25, 10},
		{112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 87, 92, 20, 8},
		{113, 114, 0, 0x0L, RADIO1, (void*)" relative", 20, 104, 25, 8},
		{114, 115, 0, 0x0L, EDTEXT, &sTxt2[1], 60, 104, 25, 10},
		{115, 0, 0, 0x0L, LTEXT, (void*)"%", 87, 104, 10, 8},
		{300, 301, 0, 0x0L, RTEXT, (void*)"point 1 x", 15, 40, 28, 8},
		{301, 302, 0, 0x0L, EDVAL1, &pos1.fx, 46, 40, 35, 10},
		{302, 303, 0, 0x0L, RTEXT, (void*)"y", 15, 52, 28, 8},
		{303, 304, 0, 0x0L, EDVAL1, &pos1.fy, 46, 52, 35, 10},
		{304, 305, 0, 0x0L, RTEXT, (void*)"point 2 x", 15, 70, 28, 8},
		{305, 306, 0, 0x0L, EDVAL1, &pos2.fx, 46, 70, 35, 10},
		{306, 307, 0, 0x0L, RTEXT, (void*)"y", 15, 82, 28, 8},
		{307, 308, 0, 0x0L, EDVAL1, &pos2.fy, 46, 82, 35, 10},
		{308, 309, 0, HIDDEN, RTEXT, (void*)"box width", 15, 100, 28, 8},
		{309, 0, 0, HIDDEN | LASTOBJ, EDVAL1, &size, 46, 100, 35, 10},
		};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmpType = type;
	FillDEF newFill;
	LineDEF newLine, newHatchLine;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT n_pos;
	double tmpVal, o_size, n_size;
	bool bRet = false;
	GraphObj *ppar = parent;

	if(!parent) return false;
	memcpy(&newHatchLine, &Hatchline, sizeof(LineDEF));
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Outline, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
	if(type & BAR_RELWIDTH) {
		WriteNatFloatToBuff(sTxt2, size);
		WriteNatFloatToBuff(sTxt1, DefSize(SIZE_BAR));
		}
	else {
		WriteNatFloatToBuff(sTxt1, size);
		rlp_strcpy(sTxt2, 20, " 50");
		}
	Dlg = new DlgRoot(BoxDlg, data);
	if(type & BAR_WIDTHDATA) {
		Dlg->ShowItem(105, false);
		Dlg->ShowItem(308, true);		Dlg->ShowItem(309, true);
		}
	if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
	else Dlg->SetCheck(110, 0L, true);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box properties");
	Dlg->GetValue(309, &o_size);
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 290, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:								//accept for this object
		case 2:								//   or all objects of plot
			Undo.SetDisp(cdisp);
			OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
			if(newFill.hatch) memcpy(&newHatchLine, newFill.hatch, sizeof(LineDEF));
			newFill.hatch = &newHatchLine;
			if(type & BAR_WIDTHDATA) Dlg->GetValue(309, &n_size);
			else {
				if(Dlg->GetCheck(113)) {
					tmpType |= BAR_RELWIDTH;
					Dlg->GetValue(114, &n_size);
					}
				else {
					tmpType &= ~BAR_RELWIDTH;
					Dlg->GetValue(111, &n_size);
					}
				}
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:				//new setting for current box
		if(cmpLineDEF(&Outline, &newLine)) {
			Undo.Line(parent, &Outline, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&Outline, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&Hatchline, &newHatchLine)) {
			Undo.Line(parent, &Hatchline, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&Hatchline, &newHatchLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&Fill, &newFill)) {
			Undo.Fill(parent, &Fill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&Fill, &newFill, sizeof(FillDEF));
			}
		Fill.hatch = &Hatchline;
		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
		else n_pos.fx = pos1.fx;
		if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
		else n_pos.fy = pos1.fy;
		undo_flags = CheckNewLFPoint(&pos1, &pos1, &n_pos, parent, undo_flags);
		if(Dlg->GetValue(305, &tmpVal)) n_pos.fx = tmpVal;
		else n_pos.fx = pos2.fx;
		if(Dlg->GetValue(307, &tmpVal)) n_pos.fy = tmpVal;
		else n_pos.fy = pos2.fy;
		undo_flags = CheckNewLFPoint(&pos2, &pos2, &n_pos, parent, undo_flags);
		undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		break;
	case 2:				//new settings to all boxes of plot
		if(type != tmpType || Outline.width != newLine.width || o_size != n_size) {
			Undo.ValInt(this, &type, 0L);			//dummy: all following have UNDO_CONTINUE
			undo_flags |= UNDO_CONTINUE;
			if(parent->parent && parent->parent->Id == GO_STACKBAR) ppar = parent->parent;
			}
		else if(newLine.color != Outline.color || cmpFillDEF(&Fill, &newFill)) {
			Undo.ValInt(this, &type, 0L);			//dummy: all following have UNDO_CONTINUE
			}
		ppar->Command(CMD_SAVE_BARS_CONT, 0L, 0L);
		ppar->Command(CMD_BOX_TYPE, (void*)(& tmpType), 0L);
		ppar->SetSize(SIZE_BOX_LINE, newLine.width);
		ppar->SetSize(SIZE_BOX, n_size);
		parent->SetColor(COL_BOX_LINE, newLine.color);
		parent->Command(CMD_BOX_FILL, &newFill, 0L);
		bRet = true;
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Whisker properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *WhiskerDlgTmpl =
		"1,2,,DEFAULT,PUSHBUTTON,1,100,10,64,12\n"
		"2,3,,,PUSHBUTTON,2,100,25,64,12\n"
		"3,4,,,PUSHBUTTON,-2, 100, 40, 64, 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,500,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,55,28,8\n"
		"104,105,,,EDVAL1,9,46,55,25,10\n"
		"105,106,,,LTEXT,-3,73,55,20,8\n"
		"106,107,,,RTEXT,10,15,70,28,8\n"
		"107,,,OWNDIALOG,COLBUTT,11,46,70,25,10\n"
		"300,301,,,RTEXT,12,15,30,28,8\n"
		"301,302,,,EDVAL1,13,46,30,35,10\n"
		"302,303,,,RTEXT,-5,15,42,28,8\n"
		"303,304,,,EDVAL1,14,46,42,35,10\n"
		"304,305,,,RTEXT,15,15,55,28,8\n"
		"305,306,,,EDVAL1,16,46,55,35,10\n"
		"306,307,,,RTEXT,-5,15,67,28,8\n"
		"307,308,,,EDVAL1,17,46,67,35,10\n"
		"308,309,,,LTEXT,18,10,85,70,8\n"
		"309,,,,EDTEXT,19,10,95,80,10\n"
		"500,501,,EXRADIO,ODBUTTON,20,32,40,18,18\n"
		"501,502,,EXRADIO,ODBUTTON,20,14,40,18,18\n"
		"502,503,,EXRADIO,ODBUTTON,20,50,40,18,18\n"
		"503,504,,EXRADIO,ODBUTTON,20,68,40,18,18\n"
		"504,,,LASTOBJ,LTEXT,-27,14,30,30,9";
bool
Whisker::PropertyDlg()
{
	TabSHEET tab1 = {0, 38, 10, "Whisker"};
	TabSHEET tab2 = {65, 90, 10, "Edit"};
	TabSHEET tab3 = {38, 65, 10, "Style"};
	void *dyndata[] = {(void*)"Apply to WHISKER", (void*)"Apply to PLOT", (void*)&tab1,
		(void*)&tab3, (void*)&tab2, (void*)"cap width", (void*)&size, (void*)"line width",
		(void*)&LineDef.width, (void*)"line color", (void *)&LineDef.color, (void*)"point 1 x",
		(void*)&pos1.fx, (void*)&pos1.fy, (void*)"point 2 x", (void*)&pos2.fx, (void*)&pos2.fy,
		(void*)"description:", (void*)name, (void*)(OD_WhiskerTempl)};
	DlgInfo *ErrDlg = CompileDialog(WhiskerDlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmp_type;
	DWORD undo_flags = 0L, n_col = LineDef.color;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT n_pos;
	double tmpVal, o_size, n_size, o_lw, n_lw;
	bool bRet = false;
	char desc[80];

	if(!parent) return false;
	desc[0] = 0;	tmp_type = type;
	Dlg = new DlgRoot(ErrDlg, data);
	Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lw);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 339, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 500:	case 501:	case 502:	case 503:
			tmp_type &= ~0x0f;	tmp_type |= (res-500);	res = -1;
			break;
		case 1:								//accept for this object
		case 2:								//   or all objects of plot
			Undo.SetDisp(cdisp);			Dlg->GetValue(101, &n_size);
			Dlg->GetValue(104, &n_lw);		Dlg->GetColor(107, &n_col);
			desc[0] = 0;					Dlg->GetText(309, desc, 80);
			break;
			}
		}while (res <0);
	switch (res) {
	case 1:				//new setting for current whisker
		undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
		else n_pos.fx = pos1.fx;
		if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
		else n_pos.fy = pos1.fy;
		undo_flags = CheckNewLFPoint(&pos1, &pos1, &n_pos, parent, undo_flags);
		if(Dlg->GetValue(305, &tmpVal)) n_pos.fx = tmpVal;
		else n_pos.fx = pos2.fx;
		if(Dlg->GetValue(307, &tmpVal)) n_pos.fy = tmpVal;
		else n_pos.fy = pos2.fy;
		undo_flags = CheckNewLFPoint(&pos2, &pos2, &n_pos, parent, undo_flags);
		undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
		undo_flags = CheckNewInt(&type, type, tmp_type, parent, undo_flags);
		undo_flags = CheckNewFloat(&LineDef.width, o_lw, n_lw, parent, undo_flags);
		undo_flags = CheckNewDword(&LineDef.color, LineDef.color, n_col, parent, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		break;
	case 2:				//new settings to all whiskers of plot
		if(o_size == n_size && type == tmp_type && o_lw == n_lw 
			&& n_col == LineDef.color && !desc[0] && !name) break;
		parent->Command(CMD_SAVE_ERRS, 0L, 0L);
		if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 0L);
		parent->SetSize(SIZE_WHISKER, n_size);
		parent->SetSize(SIZE_WHISKER_LINE, n_lw);
		parent->SetColor(COL_WHISKER, n_col);
		parent->Command(CMD_WHISKER_STYLE, &tmp_type, 0L);
		bRet = true;
		break;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(ErrDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Drop line properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
DropLine::PropertyDlg()
{
	TabSHEET tab1 = {0, 21, 10, "Line"};
	TabSHEET tab2 = {21, 42, 10, "Edit"};
	DlgInfo LineDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 150, 25, 50, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
		{4, 300, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
		{11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
		{200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 35, 40, 28, 8},
		{201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 76, 40, 35, 10},
		{202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 35, 52, 28, 8},
		{203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 76, 52, 35, 10},
		{204, 0, 250, CHECKED | ISPARENT, GROUPBOX, (void*)" Shape ", 10, 70, 129, 50},
		{250, 251, 0, 0x0L, RTEXT, (void*)"line to:", 15, 80, 28, 8},
		{251, 252, 0, 0x0L, CHECKBOX, (void*)"left", 46, 80, 35, 8},
		{252, 253, 0, 0x0L, CHECKBOX, (void*)"right", 46, 90, 35, 8},
		{253, 254, 0, 0x0L, CHECKBOX, (void*)"y-axis", 46, 100, 35, 8},
		{254, 255, 0, 0x0L, CHECKBOX, (void*)"top", 86, 80, 35, 8},
		{255, 256, 0, 0x0L, CHECKBOX, (void*)"bottom", 86, 90, 35, 8},
		{256, 0, 0, LASTOBJ, CHECKBOX, (void*)"x-axis", 86, 100, 35, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmptype;
	bool bRet = false;
	LineDEF newLine;
	DWORD undo_flags = 0L;
	anyOutput * cdisp = Undo.cdisp;
	lfPOINT o_pos, n_pos;

	if(!parent) return false;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	Dlg = new DlgRoot(LineDlg, data);
	Dlg->SetCheck(251, 0L, type & DL_LEFT ? true : false);
	Dlg->SetCheck(252, 0L, type & DL_RIGHT ? true : false);
	Dlg->SetCheck(253, 0L, type & DL_YAXIS ? true : false);
	Dlg->SetCheck(254, 0L, type & DL_TOP ? true : false);
	Dlg->SetCheck(255, 0L, type & DL_BOTTOM ? true : false);
	Dlg->SetCheck(256, 0L, type & DL_XAXIS ? true : false);
	Dlg->GetValue(201, &o_pos.fx);		Dlg->GetValue(203, &o_pos.fy);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:							//this line
		case 2:							//all lines of plot
			Undo.SetDisp(cdisp);		tmptype = 0;
			if(Dlg->GetCheck(251)) tmptype |= DL_LEFT;
			if(Dlg->GetCheck(252)) tmptype |= DL_RIGHT;
			if(Dlg->GetCheck(253)) tmptype |= DL_YAXIS;
			if(Dlg->GetCheck(254)) tmptype |= DL_TOP;
			if(Dlg->GetCheck(255)) tmptype |= DL_BOTTOM;
			if(Dlg->GetCheck(256)) tmptype |= DL_XAXIS;
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			break;
			}
		}while (res < 0);
	if(res == 1){						//Apply to line
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(this, &LineDef, undo_flags);
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			undo_flags |= UNDO_CONTINUE;
			}
		Dlg->GetValue(201, &n_pos.fx);		Dlg->GetValue(203, &n_pos.fy);
		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, this, undo_flags);
		undo_flags = CheckNewInt(&type, type, tmptype, this, undo_flags);
		if (undo_flags & UNDO_CONTINUE) bModified = true;
		bRet = true;
		}
	else if(res == 2) {					//Apply to plot
		if(cmpLineDEF(&LineDef, &newLine) || type != tmptype) {
			parent->Command(CMD_SAVE_DROPLINES, 0L, 0L);
			if(cmpLineDEF(&LineDef, &newLine)) parent->Command(CMD_DL_LINE, (void*)&newLine, 0L);
			if(type != tmptype) parent->Command(CMD_DL_TYPE, (void*)(&tmptype), 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Drop line properties: DropLine 3D
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
DropLine3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 21, 10, "Line"};
	TabSHEET tab2 = {21, 42, 10, "Edit"};
	DlgInfo LineDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 150, 25, 50, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
		{4, 300, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
		{11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
		{200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 35, 30, 28, 8},
		{201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 76, 30, 35, 10},
		{202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 35, 42, 28, 8},
		{203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 76, 42, 35, 10},
		{204, 205, 0, 0x0L, RTEXT, (void*)"z-value", 35, 54, 28, 8},
		{205, 240, 0, 0x0L, EDVAL1, &fPos.fz, 76, 54, 35, 10},
		{240, 0, 250, CHECKED | ISPARENT, GROUPBOX, (void*)" Shape ", 10, 70, 129, 50},
		{250, 251, 0, 0x0L, RTEXT, (void*)"line to:", 15, 80, 28, 8},
		{251, 252, 0, 0x0L, CHECKBOX, (void*)"bottom", 46, 80, 35, 8},
		{252, 253, 0, 0x0L, CHECKBOX, (void*)"top", 86, 80, 35, 8},
		{253, 254, 0, 0x0L, CHECKBOX, (void*)"back", 46, 90, 35, 8},
		{254, 255, 0, 0x0L, CHECKBOX, (void*)"front", 86, 90, 35, 8},
		{255, 256, 0, 0x0L, CHECKBOX, (void*)"left", 46, 100, 35, 8},
		{256, 0, 0, LASTOBJ, CHECKBOX, (void*)"right", 86, 100, 35, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res, tmptype, i;
	bool bRet = false;
	LineDEF newLine;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	fPOINT3D o_pos, n_pos;

	if(!parent) return false;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	Dlg = new DlgRoot(LineDlg, data);
	for(i = 0; i < 6; i++) {
		Dlg->SetCheck(251+i, 0L, (type & (1<<i)) ? true : false);
		}
	Dlg->GetValue(201, &o_pos.fx);		Dlg->GetValue(203, &o_pos.fy);
	Dlg->GetValue(205, &o_pos.fz);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:							//this line
		case 2:							//all lines of plot
			Undo.SetDisp(cdisp);
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			for(i = tmptype = 0; i < 6; i++) {
				tmptype |= Dlg->GetCheck(251+i) ? 1<<i : 0;
				}
			break;
			}
		}while (res < 0);
	if(res == 1){						//Apply to line
		if(cmpLineDEF(&Line, &newLine)) {
			Undo.Line(this, &Line, undo_flags);
			memcpy(&Line, &newLine, sizeof(LineDEF));
			undo_flags |= UNDO_CONTINUE;
			}
		Dlg->GetValue(201, &n_pos.fx);		Dlg->GetValue(203, &n_pos.fy);
		Dlg->GetValue(205, &n_pos.fz);
		if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy || n_pos.fz != o_pos.fz) {
			Undo.ValLFP3D(this, &fPos, undo_flags);
			memcpy(&fPos, &n_pos, sizeof(fPOINT3D));
			undo_flags |= UNDO_CONTINUE;
			}
		undo_flags = CheckNewInt(&type, type, tmptype, this, undo_flags);
		if (undo_flags & UNDO_CONTINUE) bModified = true;
		bRet = true;
		}
	else if(res == 2) {					//Apply to plot
		if(cmpLineDEF(&Line, &newLine) || type != tmptype) {
			parent->Command(CMD_SAVE_DROPLINES, 0L, 0L);
			if(cmpLineDEF(&Line, &newLine)) parent->Command(CMD_DL_LINE, (void*)&newLine, 0L);
			if(type != tmptype) parent->Command(CMD_DL_TYPE, (void*)(&tmptype), 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// sphere (ball) properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Sphere::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Ball"};
	TabSHEET tab2 = {22, 45, 10, "Edit"};
	FillDEF newFill;
	char *type_text[] = {Units[defs.cUnits].display, "[x-data]", "[y-data]", "[z-data]"};
	DlgInfo BallDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BALL", 110, 10, 50, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 110, 25, 50, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 110, 40, 50, 12},
		{4, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 100, 80},
		{11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 100, 80},
		{100, 101, 0, 0x0L, RTEXT, (void*)"ball size", 15, 35, 28, 8},
		{101, 102, 0, 0x0L, INCDECVAL1, &size, 46, 35, 32, 10},
		{102, 103, 0, 0x0L, LTEXT, (void*)type_text[type < 4 ? type : 0], 80, 35, 15, 8},
		{103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 47, 28, 8},
		{104, 105, 0, 0x0L, INCDECVAL1, &Line.width, 46, 47, 32, 10},
		{105, 106, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 80, 47, 15, 8},
		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 59, 28, 8},
		{107, 108, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 46, 59, 25, 10},
		{108, 109, 0, 0x0L, RTEXT, (void*)"fill color", 15, 71, 28, 8},
		{109, 0, 0, OWNDIALOG, SHADE3D, &newFill, 46, 71, 25, 10},
		{200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 15, 35, 28, 8},
		{201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 46, 35, 35, 10},
		{202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 15, 47, 28, 8},
		{203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 46, 47, 35, 10},
		{204, 205, 0, 0x0L, RTEXT, (void*)"z-value", 15, 59, 28, 8},
		{205, 0, 0, LASTOBJ, EDVAL1, &fPos.fz, 46, 59, 35, 10}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res;
	bool bRet = false, bContinue = false;
	fPOINT3D n_pos, o_pos;
	DWORD new_lcolor = Line.color, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	double o_size, n_size, o_lsize, n_lsize;

	if(!parent) return false;
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	Dlg = new DlgRoot(BallDlg, data);
	Dlg->GetValue(201, &o_pos.fx);			Dlg->GetValue(203, &o_pos.fy);
	Dlg->GetValue(205, &o_pos.fz);			Dlg->GetValue(101, &o_size);
	Dlg->GetValue(104, &o_lsize);
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 220, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(bContinue) res = -1;
			bContinue = false;
			break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);			Dlg->GetColor(107, &new_lcolor);
			Dlg->GetValue(101, &n_size);	Dlg->GetValue(104, &n_lsize);
			break;
		case 109:
			Dlg->DoPlot(0L);				bContinue = true;
			break;
			}
		}while (res < 0);
	if(res == 1){
		Dlg->GetValue(201, &n_pos.fx);		Dlg->GetValue(203, &n_pos.fy);
		Dlg->GetValue(205, &n_pos.fz);
		if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy || n_pos.fz != o_pos.fz) {
			Undo.ValLFP3D(this, &fPos, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&fPos, &n_pos, sizeof(fPOINT3D));	parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			}
		undo_flags = CheckNewFloat(&size, o_size, n_size, this, undo_flags);
		undo_flags = CheckNewFloat(&Line.width, o_lsize, n_lsize, this, undo_flags);
		undo_flags = CheckNewDword(&Line.color, Line.color, new_lcolor, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
		undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = bModified = true;
		}
	else if(res == 2) {
		if(cmpFillDEF(&Fill, &newFill) || n_size != o_size || n_lsize != o_lsize ||
			new_lcolor != Line.color) {
			parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
			if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_SYM_FILL, &newFill, 0L);
			if(n_size != o_size) parent->SetSize(SIZE_SYMBOL, n_size);
			if(n_lsize != o_lsize) parent->SetSize(SIZE_SYM_LINE, n_lsize);
			if(new_lcolor != Line.color) parent->SetColor(COL_SYM_LINE, new_lcolor);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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;
	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 cb, res;
	bool bRet = false;
	DWORD new_lcolor = Line.color, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	double o_lsize, n_lsize, o_rbw, n_rbw, o_rbz, n_rbz;

	if(!parent) return false;
	if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	if(parent->Id == GO_RIBBON && parent->type == 1) {
		rb_width = parent->GetSize(SIZE_CELLWIDTH) *100.0;
		rb_z = parent->GetSize(SIZE_ZPOS);
		}
	Dlg = new DlgRoot(PlaneDlg, data);
	Dlg->GetValue(101, &o_lsize);		Dlg->GetValue(202, &o_rbw);
	Dlg->GetValue(205, &o_rbz);
	if(parent && ((parent->Id==GO_RIBBON && parent->type > 1) || parent->Id==GO_GRID3D))
		Dlg->ShowItem(200, false);								//paravent plot
	if(parent->Id == GO_RIBBON && parent->type >2) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Surface Properties");
	else if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:		case 2:
			Undo.SetDisp(cdisp);				Dlg->GetColor(104, &new_lcolor);
			Dlg->GetValue(101, &n_lsize);		Dlg->GetValue(202, &n_rbw);
			Dlg->GetValue(205, &n_rbz);
			break;
			}
		}while (res < 0);
	if(res == 1){
		undo_flags = CheckNewFloat(&Line.width, o_lsize, n_lsize, this, undo_flags);
		undo_flags = CheckNewDword(&Line.color, Line.color, new_lcolor, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
		undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bRet = true;
		}
	else if(res == 2) {
		if(cmpFillDEF(&Fill, &newFill) || n_lsize != o_lsize || new_lcolor != Line.color ||
			o_rbw != n_rbw || o_rbz != n_rbz) {
			parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
			if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_SYM_FILL, &newFill, 0L);
			if(n_lsize != o_lsize) parent->SetSize(SIZE_SYM_LINE, n_lsize);
			if(new_lcolor != Line.color) parent->SetColor(COL_POLYLINE, new_lcolor);
			if(parent->Id == GO_RIBBON && parent->type == 1) {
				if(o_rbw != n_rbw) parent->SetSize(SIZE_CELLWIDTH, n_rbw/100.0);
				if(o_rbz != n_rbz) parent->SetSize(SIZE_ZPOS, n_rbz);
				}
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// properties of 3D column
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Brick::PropertyDlg()
{
	TabSHEET tab1 = {0, 50, 10, "Size & Color"};
//	TabSHEET tab2 = {50, 90, 10, "Baseline"};
	TabSHEET tab3 = {50, 80, 10, "Edit"};
	FillDEF newFill;
	DlgInfo ColumnDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to COLUMN", 130, 10, 65, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 65, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 65, 12},
		{4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
		{5, 7, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
//		{6, 7, 0, ISPARENT, SHEET, &tab2, 5, 10, 120, 120},
		{7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 120},
		{100, 101, 0, 0x0L, RTEXT, (void*)"outline width", 18, 30, 40, 8},
		{101, 102, 0, 0x0L, EDVAL1, &Line.width, 60, 30, 25, 10},
		{102, 103, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 30, 20, 8},
		{103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 18, 42, 40, 8},
		{104, 105, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 60, 42, 25, 10},
		{105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 18, 54, 40, 8},
		{106, 107, 0, OWNDIALOG, SHADE3D, &newFill, 60, 54, 25, 10},
		{107, 108, 0, 0x0L, RTEXT, (void*)"column width", 18, 74, 40, 8},
		{108, 109, 0, 0x0L, EDVAL1, &width, 60, 74, 25, 10},
		{109, 110, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 74, 20, 8},
		{110, 111, 0, 0x0L, RTEXT, (void*)"column depth", 18, 86, 40, 8},
		{111, 112, 0, 0x0L, EDVAL1, &depth, 60, 86, 25, 10},
		{112, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 86, 20, 8},
		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 30, 35, 8},
		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 50, 30, 30, 10},
		{302, 303, 0, 0x0L, RTEXT, (void*)"base (y)", 10, 75, 35, 8},
		{303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 50, 75, 30, 10},
		{304, 305, 0, 0x0L, RTEXT, (void*)"z-value", 10, 42, 35, 8},
		{305, 306, 0, 0x0L, EDVAL1, &fPos.fz, 50, 42, 30, 10},
		{306, 307, 0, 0x0L, RTEXT, (void*)"height", 10, 87, 35, 8},
		{307, 0, 0, LASTOBJ, EDVAL1, &height, 50, 87, 30, 10}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res;
	bool bRet = false;
	DWORD col1 = Line.color, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	double o_lw = Line.width, n_lw, o_height = height, n_height, o_width = width, n_width;
	double o_depth = depth, n_depth;
	fPOINT3D o_pos, n_pos;

	if(!parent) return false;
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	Dlg = new DlgRoot(ColumnDlg, data);
	Dlg->GetValue(101, &o_lw);		Dlg->GetValue(301, &o_pos.fx);
	Dlg->GetValue(303, &o_pos.fy);	Dlg->GetValue(305, &o_pos.fz);
	Dlg->GetValue(307, &o_height);	Dlg->GetValue(108, &o_width);
	Dlg->GetValue(111, &o_depth);
	memcpy(&n_pos, &o_pos, sizeof(fPOINT3D));
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 405, 296, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:		case 2:
			Undo.SetDisp(cdisp);			Dlg->GetColor(104, &col1);
			Dlg->GetValue(101, &n_lw);		Dlg->GetValue(301, &n_pos.fx);
			Dlg->GetValue(303, &n_pos.fy);	Dlg->GetValue(305, &n_pos.fz);
			Dlg->GetValue(307, &n_height);	Dlg->GetValue(108, &n_width);
			Dlg->GetValue(111, &n_depth);
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:				//new setting for current column only
		undo_flags = CheckNewFloat(&Line.width, o_lw, n_lw, this, undo_flags);
		undo_flags = CheckNewDword(&Line.color, Line.color, col1, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
		undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
		undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
		if(o_pos.fx != n_pos.fx || o_pos.fy != n_pos.fy || o_pos.fz != n_pos.fz) {
			Undo.ValLFP3D(this, &fPos, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&fPos, &n_pos, sizeof(fPOINT3D));	parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			}
		undo_flags = CheckNewFloat(&height, o_height, n_height, this, undo_flags);
		if(o_height != n_height) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
		undo_flags = CheckNewFloat(&width, o_width, n_width, this, undo_flags);
		undo_flags = CheckNewFloat(&depth, o_depth, n_depth, this, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bModified = bRet = true;
		break;
	case 2:
		if(cmpFillDEF(&Fill, &newFill) || o_lw != n_lw || Line.color != col1 ||
			o_pos.fy != n_pos.fy || n_width != o_width || o_depth != n_depth) {
			parent->Command(CMD_SAVE_BARS, 0L, 0L);
			if(o_pos.fy != n_pos.fy){
				parent->Command(CMD_MRK_DIRTY, 0L, 0L);
				parent->SetSize(SIZE_BAR_BASE, n_pos.fy);
				}
			if(n_lw != o_lw) parent->SetSize(SIZE_BAR_LINE, n_lw);
			if(n_width != o_width) parent->SetSize(SIZE_BAR, n_width);
			if(o_depth != n_depth) parent->SetSize(SIZE_BAR_DEPTH, n_depth);
			if(Line.color != col1) parent->SetColor(COL_BAR_LINE, col1);
			if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_BAR_FILL, &newFill, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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"};
	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;
	double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
	int cb, res, tmptype = type, undo_level = *Undo.pcb;
	bool bRet = false;
	DWORD o_col, n_col, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(!(Dlg = new DlgRoot(ArrowDlg, data))) return false;
	Dlg->GetValue(301, &o_pos2.fx);		Dlg->GetValue(303, &o_pos2.fy);
	Dlg->GetValue(305, &o_pos2.fz);		Dlg->GetValue(307, &o_pos1.fx);
	Dlg->GetValue(309, &o_pos1.fy);		Dlg->GetValue(311, &o_pos1.fz);
	Dlg->GetValue(101, &o_cw);			Dlg->GetValue(104, &o_cl);
	Dlg->GetValue(107, &o_lw);			Dlg->GetColor(110, &o_col);
	switch(type & 0xff) {
	case ARROW_LINE:		Dlg->SetCheck(201, 0L, true);		break;
	case ARROW_TRIANGLE:	Dlg->SetCheck(202, 0L, true);		break;
	default:				Dlg->SetCheck(200, 0L, true);		break;
		}
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 200:	tmptype = ARROW_NOCAP;		res = -1;	break;
		case 201:	tmptype = ARROW_LINE;		res = -1;	break;
		case 202:	tmptype = ARROW_TRIANGLE;	res = -1;	break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);
			Dlg->GetValue(301, &n_pos2.fx);		Dlg->GetValue(303, &n_pos2.fy);
			Dlg->GetValue(305, &n_pos2.fz);		Dlg->GetValue(307, &n_pos1.fx);
			Dlg->GetValue(309, &n_pos1.fy);		Dlg->GetValue(311, &n_pos1.fz);
			Dlg->GetValue(101, &n_cw);			Dlg->GetValue(104, &n_cl);
			Dlg->GetValue(107, &n_lw);			Dlg->GetColor(110, &n_col);
			break;
			}
		}while (res <0);
	switch (res) {
	case 1:				//new setting for current arrow
		if(n_pos1.fx != o_pos1.fx || n_pos1.fy != o_pos1.fy ||
			n_pos1.fz != o_pos1.fz){
			Undo.ValLFP3D(this, &fPos1, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&fPos1, &n_pos1, sizeof(fPOINT3D));
			parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			}
		if(n_pos2.fx != o_pos2.fx || n_pos2.fy != o_pos2.fy ||
			n_pos2.fz != o_pos2.fz){
			Undo.ValLFP3D(this, &fPos2, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&fPos2, &n_pos2, sizeof(fPOINT3D));
			parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			}
		if((type & 0xff) != (tmptype & 0xff)){
			Undo.ValInt(this, &type, undo_flags);
			type &= ~0xff;	type |= (tmptype & 0xff);	undo_flags |= UNDO_CONTINUE;
			}
		undo_flags = CheckNewFloat(&cw, o_cw, n_cw, this, undo_flags);
		undo_flags = CheckNewFloat(&cl, o_cl, n_cl, this, undo_flags);
		undo_flags = CheckNewFloat(&Line.width, o_lw, n_lw, this, undo_flags);
		undo_flags = CheckNewDword(&Line.color, o_col, n_col, this, undo_flags);
		if(undo_flags & UNDO_CONTINUE) bModified = true;
		bRet = true;
		break;
	case 2:				//new settings to all arrows of plot
		if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && (Dlg->GetCheck(312) || n_lw != o_lw
			|| n_cw != o_cw || n_cl != o_cl || o_col != n_col || type != tmptype)) {
			parent->Command(CMD_SAVE_ARROWS, 0L, 0L);
			if(Dlg->GetCheck(312)) parent->Command(CMD_ARROW_ORG3D, &n_pos1, 0L);
			if(n_lw != o_lw) parent->SetSize(SIZE_ARROW_LINE, n_lw);
			if(n_cw != o_cw) parent->SetSize(SIZE_ARROW_CAPWIDTH, n_cw);
			if(n_cl != o_cl) parent->SetSize(SIZE_ARROW_CAPLENGTH, n_cl);
			if(o_col != n_col) parent->SetColor(COL_ARROW, n_col);
			if(type != tmptype) parent->Command(CMD_ARROW_TYPE, &tmptype, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);	delete Dlg;		free(ArrowDlg);		return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// properties of 3D data line
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Line3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Line"};
	DlgInfo LineDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 130},
		{100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 30, 130, 90}};
	DlgRoot *Dlg;
	void *hDlg;
	int cb, res;
	bool bRet = false;
	LineDEF newLine;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 314, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
	}while (res < 0);
	switch(res) {
	case 1:							//OK pressed
		Undo.SetDisp(cdisp);
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		if(cmpLineDEF(&Line, &newLine)) {
			if(parent->Id == GO_GRID3D) {
				parent->Command(CMD_SET_LINE, &newLine, 0L);
				}
			else {
				Undo.Line(this, &Line, 0L);
				memcpy(&Line, &newLine, sizeof(LineDEF));
				bModified = true;
				}
			}
		bRet = true;
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// label (text) properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Label::PropertyDlg()
{
	TabSHEET tab1 = {0, 27, 10, "Label"};
	TabSHEET tab2 = {27, 75, 10, "Font & Style"};
	TabSHEET tab3 = {75, 110, 10, "Position"};
	bool isDataLabel = ((parent) && (parent->Id == GO_PLOTSCATT || parent->Id == GO_XYSTAT || parent->Id == GO_BOXPLOT
		|| parent->Id == GO_CONTOUR));
	int bwidth = isDataLabel ? 55 : 45;
	double lspc = 100.0;
	DlgInfo LabelDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, isDataLabel ? (void*)"Apply to LABEL" : (void*)"OK", 170, 10, bwidth, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, isDataLabel ? 40 : 25, bwidth, 12},
		{3, isDataLabel ? 10 : 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 159, 100},
		{5, 6, 200, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 159, 100},
		{6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 159, 100},
		{10, 50, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 170, 25, bwidth, 12},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, 0x0L, RTEXT, (void*)"size", 30, 33, 45, 8},
		{101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 80, 33, 33, 10},
		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 33, 20, 8},
		{103, 104, 0, 0x0L, RTEXT, (void*)"color", 30, 45, 45, 8},
		{104, 107, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 80, 45, 25, 10},
		{105, 106, 0, 0x0L, LTEXT, (void*)"text:", 10, 83, 25, 8},
		{106, 0, 0, TOUCHEXIT, EDTEXT, (void*)TextDef.text, 10, 95, 149, 10},
		{107, 108, 0, 0x0L, RTEXT, (void*)"rotation", 30, 57, 45, 8},
		{108, 109, 0, 0x0L, EDVAL1, &TextDef.RotBL, 80, 57, 25, 10},
		{109, 150, 0, 0x0L, LTEXT, (void *)"deg.", 107, 57, 20, 8},
		{150, 154, 151, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 30, 69, 45, 8},
		{152, 153, 0, 0x0L, INCDECVAL1, &lspc, 80, 69, 33, 10},
		{153, 0, 0, 0x0L, LTEXT, (void *)"%", 115, 69, 20, 8},
		{154, 105, 0, 0x0L, CHECKBOX, (void*) " moveable", 80, 83, 60, 9},
		{200, 244, 221, CHECKED | ISPARENT, GROUPBOX, (void*)" font ", 17, 28, 60, 50},
		{221, 222, 0, TOUCHEXIT, RADIO1, (void*)"Helvetica", 20, 35, 45, 8},
		{222, 223, 0, TOUCHEXIT, RADIO1, (void*)"Times", 20, 45, 45, 8},
		{223, 224, 0, TOUCHEXIT, RADIO1, (void*)"Courier", 20, 55, 45, 8},
		{224, 0, 0, TOUCHEXIT, RADIO1, (void*)"Greek", 20, 65, 45, 8},
		{244, 105, 245, CHECKED | ISPARENT, GROUPBOX, (void*)" style ", 87, 28, 67, 60},
		{245, 246, 0, TOUCHEXIT, CHECKBOX, (void*)"bold", 90, 35, 25, 8},
		{246, 247, 0, TOUCHEXIT, CHECKBOX, (void*)"italic", 90, 45, 25, 8},
		{247, 248, 0, TOUCHEXIT, CHECKBOX, (void*)"underlined", 90, 55, 25, 8},
		{248, 249, 0, TOUCHEXIT, CHECKBOX, (void*)"superscript", 90, 65, 25, 8},
		{249, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"subscript", 90, 75, 25, 8},
		{300, 301, 0, 0x0L, LTEXT, (void*)"text anchor at", 10, 25, 30, 8},
		{301, 302, 0, 0x0L, RTEXT, (void*)"x", 5, 37, 15, 8},
		{302, 303, 0, 0x0L, EDVAL1, &fPos.fx, 22, 37, 45, 10},
		{303, 304, 0, 0x0L, LTEXT, (void*)0L, 69, 37, 10, 8},
		{304, 305, 0, 0x0L, RTEXT, (void*)"y", 85, 37, 10, 8},
		{305, 306, 0, 0x0L, EDVAL1, &fPos.fy, 97, 37, 45, 10},
		{306, 307, 0, 0x0L, LTEXT, (void*)0L, 144, 37, 10, 8},
		{307, 308, 0, 0x0L, LTEXT, (void*)"distance from anchor point", 10, 52, 50, 8},
		{308, 309, 0, 0x0L, RTEXT, (void*)"dx", 5, 64, 15, 8},
		{309, 310, 0, 0x0L, EDVAL1, &fDist.fx, 22, 64, 45, 10},
		{310, 311, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 69, 64, 10, 8},
		{311, 312, 0, 0x0L, RTEXT, (void*)"dy", 85, 64, 10, 8},
		{312, 313, 0, 0x0L, EDVAL1, &fDist.fy, 97, 64, 45, 10},
		{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, 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;
	bool RetVal = false, check;
	double tmp;
	DWORD undo_flags = 0x0;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT o_pos, o_dist, n_pos, n_dist;
	TextDEF OldTxtDef, NewTxtDef;
	Axis *pa;
	fmtText *fmt = 0L;

	if(!parent) return false;
	if(parent->Id == GO_MLABEL) {
		lspc = 100.0 * parent->GetSize(SIZE_LSPC);
		}
	if (lspc < 50.0) lspc = 100.0;
	if(Dlg = new DlgRoot(LabelDlg, data)) {
		if(parent->Id == GO_MLABEL) Dlg->ShowItem(150, true);
		Dlg->TextFont(221, FONT_HELVETICA);		Dlg->TextFont(222, FONT_TIMES);
		Dlg->TextFont(223, FONT_COURIER);		Dlg->TextFont(224, FONT_GREEK);
		Dlg->TextStyle(205, TXS_BOLD);			Dlg->TextStyle(206, TXS_ITALIC);
		Dlg->TextStyle(207, TXS_UNDERLINE);		Dlg->TextStyle(207, TXS_SUPER);
		Dlg->TextStyle(207, TXS_SUB);
		if(moveable){
			Dlg->SetCheck(154, 0L, true);
			}
		switch(TextDef.Font) {
		case FONT_TIMES:	Dlg->SetCheck(222, 0L, true);	break;
		case FONT_COURIER:	Dlg->SetCheck(223, 0L, true);	break;
		case FONT_GREEK:	Dlg->SetCheck(224, 0L, true);	break;
		default:			Dlg->SetCheck(221, 0L, true);	break;
			}
		if(TextDef.Style & TXS_BOLD) Dlg->SetCheck(245, 0L, true);
		if(TextDef.Style & TXS_ITALIC) Dlg->SetCheck(246, 0L, true);
		if(TextDef.Style & TXS_UNDERLINE) Dlg->SetCheck(247, 0L, true);
		if(TextDef.Style & TXS_SUPER) Dlg->SetCheck(248, 0L, true);
		if(TextDef.Style & TXS_SUB) Dlg->SetCheck(249, 0L, true);
		}
	else return false;
	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	switch(flags & 0x03) {
	case LB_X_DATA:
		Dlg->SetText(303, "[data]");
		break;
	case LB_X_PARENT:
		Dlg->SetText(303, " ");
		TmpTxt[0] = 0;
		if(parent->Id == GO_MLABEL) {
			if(parent->parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
			else if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
			}
		else {
			if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
			else if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
			}
		if(TmpTxt[0]) {
			Dlg->SetText(302, TmpTxt);			Dlg->Activate(302, false);
			}
		break;
	default:
		Dlg->SetText(303, Units[defs.cUnits].display);
		break;
		}
	switch(flags & 0x30) {
	case LB_Y_DATA:
		Dlg->SetText(306, "[data]");
		break;
	case LB_Y_PARENT:
		Dlg->SetText(306, " ");					TmpTxt[0] = 0;
		if(parent->Id == GO_MLABEL) {
			if(parent->parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
			if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
			}
		else {
			if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
			if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
			}
		if(TmpTxt[0]) {
			Dlg->SetText(305, TmpTxt);			Dlg->Activate(305, false);
			}
		break;
	default:
		Dlg->SetText(306, Units[defs.cUnits].display);
		break;
		}
	memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF));	OldTxtDef.text = 0L;
	Dlg->GetValue(101, &OldTxtDef.fSize);			Dlg->GetValue(108, &OldTxtDef.RotBL);
	memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
	o_pos.fx = fPos.fx;	o_pos.fy = fPos.fy;	o_dist.fx = fDist.fx;	o_dist.fy = fDist.fy;
	Dlg->GetValue(302, &o_pos.fx);					Dlg->GetValue(305, &o_pos.fy);
	Dlg->GetValue(309, &o_dist.fx);					Dlg->GetValue(312, &o_dist.fy);
	n_pos.fx = o_pos.fx;	n_pos.fy = o_pos.fy;	n_dist.fx = o_dist.fx;	n_dist.fy = o_dist.fy;
	hDlg = CreateDlgWnd("Label properties", 50, 50, isDataLabel ? 470 : 450, 258, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch (res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);
			}
		switch (res) {
		case 10:
			Undo.SetDisp(cdisp);
			parent->Command(CMD_SAVE_LABELS, 0L, 0L);
			undo_flags |= UNDO_CONTINUE;
		case 1:
			Dlg->GetValue(101, &NewTxtDef.fSize);	Dlg->GetColor(104, &NewTxtDef.ColTxt);
			Dlg->GetValue(108, &NewTxtDef.RotBL);	Dlg->GetInt(315, &NewTxtDef.Align);
			Dlg->GetValue(302, &n_pos.fx);			Dlg->GetValue(305, &n_pos.fy);
			Dlg->GetValue(309, &n_dist.fx);			Dlg->GetValue(312, &n_dist.fy);
			break;
		case 106:													//text modified
			if(!(Dlg->GetText(res, TmpTxt, TMP_TXT_SIZE))) TmpTxt[0] = 0;
			else {
				if(!fmt) fmt = new fmtText(0L, 0, 0, TmpTxt);
				else fmt->SetText(0L, TmpTxt, 0L, 0L);
				}
			if(fmt && TmpTxt[0] && Dlg->GetInt(106, &i)) {
				c_style = NewTxtDef.Style;	c_font = NewTxtDef.Font;
				fmt->StyleAt(i, &NewTxtDef, &c_style, &c_font);
				Dlg->SetCheck(245, 0L, TXS_BOLD == (c_style & TXS_BOLD));
				Dlg->SetCheck(246, 0L, TXS_ITALIC == (c_style & TXS_ITALIC));
				Dlg->SetCheck(247, 0L, TXS_UNDERLINE == (c_style & TXS_UNDERLINE));
				Dlg->SetCheck(248, 0L, TXS_SUPER == (c_style & TXS_SUPER));
				Dlg->SetCheck(249, 0L, TXS_SUB == (c_style & TXS_SUB));
				switch(c_font) {
				case FONT_HELVETICA:	Dlg->SetCheck(221, 0L, true);	break;
				case FONT_TIMES:		Dlg->SetCheck(222, 0L, true);	break;
				case FONT_COURIER:		Dlg->SetCheck(223, 0L, true);	break;
				case FONT_GREEK:		Dlg->SetCheck(224, 0L, true);	break;
					}
				}
			res = -1;
			break;
		case 221:	case 222:	case 223:	case 224:				//fonts
			switch (res){
			case 221:		res = FONT_HELVETICA;		break;
			case 222:		res = FONT_TIMES;			break;
			case 223:		res = FONT_COURIER;			break;
			case 224:		res = FONT_GREEK;			break;
				}
			if(!Dlg->ItemCmd(106, CMD_SETFONT, &res)) NewTxtDef.Font = res;
			res = -1;
			break;
		case 245:	case 246:	case 247:	case 248:	case 249:	//styles
			check = Dlg->GetCheck(res);
			switch (res){
			case 245:		res = TXS_BOLD;			break;
			case 246:		res = TXS_ITALIC;		break;
			case 247:		res = TXS_UNDERLINE;	break;
			case 248:		res = TXS_SUPER;		break;
			case 249:		res = TXS_SUB;			break;
				}
			if(!check) {
				res = ~res;
				if(!Dlg->ItemCmd(106, CMD_SETSTYLE, &res)) NewTxtDef.Style &= res;
				}
			else if(!Dlg->ItemCmd(106, CMD_SETSTYLE, &res)) NewTxtDef.Style |= res;
			res = -1;
			break;
			}
		}while (res < 0);
	if(res == 1 || res == 10) {
		Undo.SetDisp(cdisp);
		if(parent->Id == GO_TICK && parent->parent && parent->parent->Id == GO_AXIS)
			pa = (Axis*)parent->parent;
		else if(parent->Id == GO_MLABEL && parent->parent->Id == GO_TICK 
			&& parent->parent->parent && parent->parent->parent->Id == GO_AXIS)
			pa = (Axis*)parent->parent->parent;
		else pa = 0L;
		if(pa && (cmpTextDEF(&OldTxtDef, &NewTxtDef) || o_dist.fx != n_dist.fx ||
			o_dist.fy != n_dist.fy)){
			pa->Command(CMD_SAVE_TICKS, 0L, 0L);			undo_flags |= UNDO_CONTINUE;
			}
		i = Dlg->GetCheck(154) ? 1 : 0;
		if(i != moveable) {
			Undo.ValInt(parent, &moveable, undo_flags);
			moveable = i;									undo_flags |= UNDO_CONTINUE;
			}
		TmpTxt[0] = 0;		Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
		if(res == 1) undo_flags = CheckNewString(&TextDef.text, TextDef.text, TmpTxt, this, undo_flags);
		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
			if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
			if (pa) pa->Command(CMD_TLB_TXTDEF, &NewTxtDef, 0L);
			else if(res == 10 || parent->Id == GO_MLABEL) {
				if(parent->Command(CMD_SETTEXTDEF, &NewTxtDef, 0L))RetVal = true;
				}
			else {
				Undo.TextDef(this, &TextDef, undo_flags);
				NewTxtDef.text = TextDef.text;	memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));	
				undo_flags |= UNDO_CONTINUE;
				}
			}
		if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy) {
			if(parent->Id == GO_MLABEL) {
				if(parent->SetSize(SIZE_XPOS, n_pos.fx) || 
					parent->SetSize(SIZE_YPOS, n_pos.fy)) RetVal = true;
				}
			else {
				Undo.SaveLFP(this, &fPos, undo_flags);		undo_flags |= UNDO_CONTINUE;
				fPos.fx = n_pos.fx;		fPos.fy = n_pos.fy;
				}
			}
		if(n_dist.fx != o_dist.fx || n_dist.fy != o_dist.fy) {
			if(pa) {
				pa->SetSize(SIZE_TLB_XDIST, n_dist.fx);		pa->SetSize(SIZE_TLB_YDIST, n_dist.fy);
				}
			else if(res == 10 || parent->Id == GO_MLABEL) {
				if(n_dist.fx != o_dist.fx && parent->SetSize(SIZE_LB_XDIST, n_dist.fx)) RetVal = true;
				if(n_dist.fy != o_dist.fy && parent->SetSize(SIZE_LB_YDIST, n_dist.fy)) RetVal = true;
				}
			else {
				Undo.SaveLFP(this, &fDist, undo_flags);		undo_flags |= UNDO_CONTINUE;
				fDist.fx = n_dist.fx;	fDist.fy = n_dist.fy;
				}
			}
		if(parent->Id == GO_MLABEL && Dlg->GetValue(152, &tmp) && tmp != lspc) {
			parent->SetSize(SIZE_LSPC, tmp/100.0);	RetVal = true;
			}
		if(undo_flags & UNDO_CONTINUE) RetVal = true;
		}
	CloseDlgWnd(hDlg);
	if(fmt) delete(fmt);
	delete Dlg;
	return RetVal;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Text frame properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
TextFrame::PropertyDlg()
{
	TabSHEET tab1 = {0, 27, 10, "Text"};
	TabSHEET tab2 = {27, 57, 10, "Frame"};
	double lspc2, lspc1 = lspc2 = lspc * 100.0;
	DlgInfo TextFrmDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
		{3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 119, 100},
		{5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 119, 100},
		{50, 0, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, 0x0L, RTEXT, (void*)"size", 10, 33, 45, 8},
		{101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 60, 33, 33, 10},
		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 95, 33, 20, 8},
		{103, 104, 0, 0x0L, RTEXT, (void*)"color", 10, 45, 45, 8},
		{104, 150, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 60, 45, 25, 10},
		{150, 0, 151, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 10, 57, 45, 8},
		{152, 153, 0, 0x0L, INCDECVAL1, &lspc1, 60, 57, 33, 10},
		{153, 0, 0, 0x0L, LTEXT, (void *)"%", 95, 57, 20, 8},
		{200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 20, 30, 90, 50},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 45, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 60, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 75, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 90, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	anyOutput *cdisp = Undo.cdisp;
	int i, res;
	bool bRet = false;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	TextDEF OldTxtDef, NewTxtDef;

	if(!parent || !data) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
	if(!(Dlg = new DlgRoot(TextFrmDlg, data)))return false;
	memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF));	OldTxtDef.text = 0L;
	Dlg->GetValue(101, &OldTxtDef.fSize);			memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
	Dlg->GetValue(152, &lspc1);
	hDlg = CreateDlgWnd("Text Frame", 50, 50, 370, 258, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch (res) {
		case 1:
			Dlg->GetValue(101, &NewTxtDef.fSize);	Dlg->GetColor(104, &NewTxtDef.ColTxt);
			Dlg->GetValue(152, &lspc2);			lspc1 /= 100.0;			lspc2 /= 100.0;
			break;
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		Undo.SetDisp(cdisp);
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
		memcpy(&newFillLine, &FillLine, sizeof(LineDEF));
		if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
			Undo.TextDef(this, &TextDef, undo_flags);
			memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));	
			undo_flags |= UNDO_CONTINUE;	TextDef.text = 0L;
			}
		undo_flags = CheckNewFloat(&lspc, lspc1, lspc2, parent, undo_flags);
		if(cmpLineDEF(&Line, &newLine)) {
			Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&Line, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&FillLine, &newFillLine)) {
			Undo.Line(parent, &FillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&FillLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&Fill, &newFill)) {
			Undo.Fill(parent, &Fill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&Fill, &newFill, sizeof(FillDEF));
			}
		Fill.hatch = &FillLine;
		if(undo_flags & UNDO_CONTINUE){
			bRet = bModified = true;					lines2text();
			Undo.TextBuffer(this, &csize, &cpos, &text, undo_flags, cdisp);
			if(lines) {
				for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
				free(lines);			lines = 0L;
				}
			HideTextCursor();			cur_pos.x = cur_pos.y = 0;
			}
		}
	CloseDlgWnd(hDlg);		delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// segment properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
segment::PropertyDlg()
{
	TabSHEET tab1 = {0, 50, 10, "Size & Color"};
	TabSHEET tab2 = {50, 90, 10, "Edit"};
	DlgInfo SegDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to SEGMENT", 130, 10, 65, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 65, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 65, 12},
		{4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 115},
		{6, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 115},
		{100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 35, 90, 50},
		{109, 110, 0, 0x0L, RTEXT, (void*)"shift out (explode)", 10, 90, 55, 8},
		{110, 111, 0, 0x0L, EDVAL1, &shift, 67, 90, 25, 10},
		{111, 112, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 94, 90, 20, 8},
		{112, 0, 0, 0x0L, CHECKBOX, (void*)"enable mouse drag (moveable)", 12, 107, 100, 8},
		{200, 201, 0, 0x0L, RTEXT, (void*)"center x", 10, 30, 40, 8},
		{201, 202, 0, 0x0L, EDVAL1, &fCent.fx, 55, 30, 40, 10},
		{202, 203, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 30, 20, 8},
		{203, 204, 0, 0x0L, RTEXT, (void*)"y", 10, 42, 40, 8},
		{204, 205, 0, 0x0L, EDVAL1, &fCent.fy, 55, 42, 40, 10},
		{205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 42, 20, 8},
		{206, 207, 0, 0x0L, RTEXT, (void*)"start angle", 10, 57, 40, 8},
		{207, 208, 0, 0x0L, EDVAL1, &angle1, 55, 57, 40, 10},
		{208, 209, 0, 0x0L, LTEXT, (void*)"deg.", 98, 57, 20, 8},
		{209, 210, 0, 0x0L, RTEXT, (void*)"stop", 10, 69, 40, 8},
		{210, 211, 0, 0x0L, EDVAL1, &angle2, 55, 69, 40, 10},
		{211, 212, 0, 0x0L, LTEXT, (void*)"deg.", 98, 69, 20, 8},
		{212, 213, 0, 0x0L, RTEXT, (void*)"outer radius", 10, 84, 40, 8},
		{213, 214, 0, 0x0L, EDVAL1, &radius2, 55, 84, 40, 10},
		{214, 215, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 84, 20, 8},
		{215, 216, 0, 0x0L, RTEXT, (void*)"inner", 10, 96, 40, 8},
		{216, 217, 0, 0x0L, EDVAL1, &radius1, 55, 96, 40, 10},
		{217, 0, 0, LASTOBJ, LTEXT, (void *) Units[defs.cUnits].display, 98, 96, 20, 8}};

	DlgRoot *Dlg;
	void *hDlg;
	int res, new_mov;
	double old_r1, old_r2, old_a1, old_a2, old_shift;
	double new_r1, new_r2, new_a1, new_a2, new_shift;
	lfPOINT old_cent, new_cent;
	bool bRet = false;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&segLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&segFill, 0);
	Dlg = new DlgRoot(SegDlg, data);
	Dlg->GetValue(216, &old_r1);		new_r1 = old_r1;
	Dlg->GetValue(213, &old_r2);		new_r2 = old_r2;
	Dlg->GetValue(201, &old_cent.fx);	new_cent.fx = old_cent.fx;
	Dlg->GetValue(204, &old_cent.fy);	new_cent.fy = old_cent.fy;
	Dlg->GetValue(207, &old_a1);		new_a1 = old_a1;
	Dlg->GetValue(210, &old_a2);		new_a2 = old_a2;
	Dlg->GetValue(110, &old_shift);		new_shift = old_shift;
	if(moveable) Dlg->SetCheck(112, 0L, true);
	hDlg = CreateDlgWnd("segment properties", 50, 50, 410, 290, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 1:		case 2:
			Undo.SetDisp(cdisp);
			OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
			memcpy(&newFillLine, &segFillLine, sizeof(LineDEF));
			if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
			Dlg->GetValue(201, &new_cent.fx);			Dlg->GetValue(204, &new_cent.fy);
			Dlg->GetValue(207, &new_a1);				Dlg->GetValue(210, &new_a2);
			Dlg->GetValue(216, &new_r1);				Dlg->GetValue(213, &new_r2);
			Dlg->GetValue(110, &new_shift);
			new_mov = Dlg->GetCheck(112) ? 1 : 0;
			break;
			}
		}while (res < 0);
	switch (res) {
	case 1:				//new setting for current segment only
		undo_flags = CheckNewLFPoint(&fCent, &old_cent, &new_cent, parent, undo_flags);
		undo_flags = CheckNewFloat(&angle1, old_a1, new_a1, parent, undo_flags);
		undo_flags = CheckNewFloat(&angle2, old_a2, new_a2, parent, undo_flags);
		undo_flags = CheckNewFloat(&radius1, old_r1, new_r1, parent, undo_flags);
		undo_flags = CheckNewFloat(&radius2, old_r2, new_r2, parent, undo_flags);
		undo_flags = CheckNewFloat(&shift, old_shift, new_shift, parent, undo_flags);
		if(cmpLineDEF(&segLine, &newLine)) {
			Undo.Line(parent, &segLine, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&segLine, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) {
			Undo.Line(parent, &segFillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&segFillLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&segFill, &newFill)) {
			Undo.Fill(parent, &segFill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&segFill, &newFill, sizeof(FillDEF));
			}
		segFill.hatch = &segFillLine;
		undo_flags = CheckNewInt(&moveable, moveable, new_mov, parent, undo_flags);
		bRet = bModified = ((undo_flags & UNDO_CONTINUE) == UNDO_CONTINUE);
		break;
	case 2:				//new settings to all segments of chart
		if(new_cent.fx != old_cent.fx || new_cent.fy != old_cent.fy || new_r1 != old_r1 || 
			new_r2 != old_r2 || new_shift != old_shift || cmpLineDEF(&segLine, &newLine) ||
			(newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) || 
			cmpFillDEF(&segFill, &newFill) || new_mov != moveable) {
			parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
			if(new_cent.fx != old_cent.fx || new_cent.fy != old_cent.fy) {
				parent->SetSize(SIZE_XPOS, new_cent.fx);	parent->SetSize(SIZE_YPOS, new_cent.fy);
				}
			if(new_r1 != old_r1 || new_r2 != old_r2) {
				parent->SetSize(SIZE_RADIUS1, new_r1);		parent->SetSize(SIZE_RADIUS2, new_r2);
				}
			if(new_shift != old_shift) parent->Command(CMD_SHIFT_OUT, (void*)&new_shift, 0L);
			if(cmpLineDEF(&segLine, &newLine))parent->Command(CMD_SEG_LINE, (void*)&newLine, 0L);
			if((newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) || 
				cmpFillDEF(&segFill, &newFill)) parent->Command(CMD_SEG_FILL, (void*)&newFill, 0L);
			if(new_mov != moveable) parent->Command(CMD_SEG_MOVEABLE, (void *)&new_mov, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// polyline properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
polyline::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Line"};
	DlgInfo LineDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 50, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 130},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 30, 130, 90},
		{101, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 125, 60, 9},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 60, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 75, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 90, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 105, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb;
	anyOutput *cdisp = Undo.cdisp;
	bool bRet = false;
	LineDEF newLine;

	if(!parent) return false;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	hDlg = CreateDlgWnd("line properties", 50, 50, 410, 314, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch (res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);	break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);	break;
			}
	}while (res < 0);
	switch(res) {
	case 1:							//OK pressed
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		if(cmpLineDEF(&pgLine, &newLine)) {
			Undo.Line(this, &pgLine, 0L);
			memcpy(&pgLine, &newLine, sizeof(LineDEF));
			bModified = true;
			}
		if(Dlg->GetCheck(101)) defs.plLineDEF(&pgLine);
		bRet = true;
		break;
	case 2:							//Cancel
		if(*Undo.pcb > undo_level) {	//restore plot order
			while(*Undo.pcb > undo_level)	Undo.Restore(false, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// polygon properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
polygon::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, "Polygon"};
	DlgInfo PolygDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 102, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 102, 25, 45, 12},
		{3, 50, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 85},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
		{101, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 82, 60, 9},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 107, 52, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 127, 52, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 127, 67, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 107, 67, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	LineDEF newLine, newFillLine;
	FillDEF newFill;
	DWORD undo_flags = 0L;
	int res, undo_level = *Undo.pcb;
	anyOutput *cdisp = Undo.cdisp;
	bool bRet = false;

	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
	Dlg = new DlgRoot(PolygDlg, data);
	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	hDlg = CreateDlgWnd("polygon properties", 50, 50, 310, 224, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch(res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);		break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);	break;
			}
		}while (res < 0);
	switch (res) {
	case 1:						//OK pressed
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
		memcpy(&newFillLine, &pgFillLine, sizeof(LineDEF));
		if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
		if(cmpLineDEF(&pgLine, &newLine)) {
			Undo.Line(this, &pgLine, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&pgLine, &newLine, sizeof(LineDEF));
			}
		if(newFill.type && cmpLineDEF(&pgFillLine, &newFillLine)) {
			Undo.Line(this, &pgFillLine, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&pgFillLine, &newFillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&pgFill, &newFill)) {
			Undo.Fill(this, &pgFill, undo_flags);		undo_flags |= UNDO_CONTINUE;
			memcpy(&pgFill, &newFill, sizeof(FillDEF));
			}
		pgFill.hatch = &pgFillLine;
		if(undo_flags & UNDO_CONTINUE) bModified = true;
		if(Dlg->GetCheck(101)){
			defs.pgLineDEF(&pgLine);			defs.pgFillDEF(&pgFill);
			}
		bRet = true;
		break;
	case 2:							//Cancel
		if(*Undo.pcb > undo_level) {	//restore plot order
			while(*Undo.pcb > undo_level)	Undo.Restore(false, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// rectangle, round rectangle and ellipse properties dialogs
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
rectangle::PropertyDlg()
{
	TabSHEET tab1 = {0, 40, 10, type == 1 ? (char*)"Ellipse" :(char*)"Rectangle"};
	TabSHEET tab2 = {40, 63, 10, "Edit"};
	DlgInfo RecDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 112, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 112, 25, 45, 12},
		{3, 0, 10, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0},
		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 100, 97},
		{11, 50, 200, ISPARENT, SHEET, &tab2, 5, 10, 100, 97},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
		{101, 120, 110, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{110, 111, 0, 0x0L, RTEXT, (void*)"edge radius", 0, 79, 48, 8},
		{111, 112, 0, 0x0L, EDVAL1, &rad, 50, 79, 25, 10},
		{112, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 77, 79, 10, 8},
		{120, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 92, 60, 9},
		{200, 201, 0, 0x0L, RTEXT, (void*)"top left x", 5, 30, 40, 8},
		{201, 202, 0, 0x0L, EDVAL1, &fp1.fx, 47, 30, 38, 10},
		{202, 203, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 30, 10, 8},
		{203, 204, 0, 0x0L, RTEXT, (void*)"y", 5, 42, 40, 8},
		{204, 205, 0, 0x0L, EDVAL1, &fp1.fy, 47, 42, 38, 10},
		{205, 206, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 42, 10, 8},
		{206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 55, 40, 8},
		{207, 208, 0, 0x0L, EDVAL1, &fp2.fx, 47, 55, 38, 10},
		{208, 209, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 55, 10, 8},
		{209, 210, 0, 0x0L, RTEXT, (void*)"y", 5, 67, 40, 8},
		{210, 211, 0, 0x0L, EDVAL1, &fp2.fy, 47, 67, 38, 10},
		{211, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 67, 10, 8},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 115, 64, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 139, 64, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 139, 79, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 115, 79, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb;
	lfPOINT old_fp1, new_fp1, old_fp2, new_fp2;
	LineDEF old_Line, new_Line, old_FillLine, new_FillLine;
	FillDEF old_Fill, new_Fill;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	bool bRet = false;

	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
	if(!(Dlg = new DlgRoot(RecDlg, data)))return false;
	Dlg->GetValue(201, &old_fp1.fx);		Dlg->GetValue(204, &old_fp1.fy);
	Dlg->GetValue(207, &old_fp2.fx);		Dlg->GetValue(210, &old_fp2.fy);
	if(type != 2) Dlg->ShowItem(101, false);
	if(parent->Id ==  GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&old_Line, 0);
	OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&old_Fill, 0);
	if(old_Fill.hatch) memcpy(&old_FillLine, old_Fill.hatch, sizeof(LineDEF));
	old_Fill.hatch = &old_FillLine;
	hDlg = CreateDlgWnd(type == 1 ? (char*)"ellipse properties":
		type == 2 ? (char*)"rounded rectangle" : (char*)"rectangle properties", 
		50, 50, 330, 248, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch(res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);		break;
		case 1:		case 2:
			Undo.SetDisp(cdisp);	break;
			}
		}while (res < 0);
	switch (res) {
	case 1:						//OK pressed
		Dlg->GetValue(201, &new_fp1.fx);		Dlg->GetValue(204, &new_fp1.fy);
		Dlg->GetValue(207, &new_fp2.fx);		Dlg->GetValue(210, &new_fp2.fy);
		undo_flags = CheckNewLFPoint(&fp1, &old_fp1, &new_fp1, this, undo_flags);
		undo_flags = CheckNewLFPoint(&fp2, &old_fp2, &new_fp2, this, undo_flags);
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&new_Line, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&new_Fill, 0);
		if(new_Fill.hatch) memcpy(&new_FillLine, new_Fill.hatch, sizeof(LineDEF));
		new_Fill.hatch = &new_FillLine;
		if(cmpLineDEF(&old_Line, &new_Line)) {
			Undo.Line(this, &Line, undo_flags);
			undo_flags |= UNDO_CONTINUE;
			memcpy(&Line, &new_Line, sizeof(LineDEF));
			}
		if(new_Fill.type && cmpLineDEF(&old_FillLine, &new_FillLine)) {
			Undo.Line(this, &FillLine, undo_flags);
			undo_flags |= UNDO_CONTINUE;
			memcpy(&FillLine, &new_FillLine, sizeof(LineDEF));
			}
		if(cmpFillDEF(&Fill, &new_Fill)) {
			Undo.Fill(this, &Fill, undo_flags);
			undo_flags |= UNDO_CONTINUE;
			memcpy(&Fill, &new_Fill, sizeof(FillDEF));
			}
		Fill.hatch = &FillLine;
		if(type == 2) Dlg->GetValue(111, &rad);
		else rad = 0.0;
		if(Dlg->GetCheck(120)){
			defs.pgLineDEF(&Line);			defs.pgFillDEF(&Fill);
			if(type == 2)defs.rrectRad(rad);
			}
		if(undo_flags) bModified = true;
		bRet = true;
		break;
	case 2:							//Cancel
		if(*Undo.pcb > undo_level) {	//restore plot order
			while(*Undo.pcb > undo_level)	Undo.Restore(false, 0L);
			bRet = true;
			}
		break;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a bar chart: note this is a PlotScatt function
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
PlotScatt::CreateBarChart()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Details"};
	double start = 1.0, step = 1.0, bw = 60.0;
	DlgInfo BarDlg[] = {
		{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, 110},
		{5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 110},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
		{101, 102, 0, 0x0L, RANGEINPUT, TmpTxt, 10, 38, 110, 10},
		{102, 0, 110, ISPARENT | CHECKED, GROUPBOX, (void*)" style ", 10, 55, 110, 61}, 
		{110, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 62, 90, 50},
		{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*)"step value", 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, 0, 0, LASTOBJ, LTEXT, (void*)"%", 95, 65, 8, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	bool bRet = false;
	int k, l, n, ic, res;
	double x, y;
	AccRange *rY = 0L;
	LineDEF Line;
	FillDEF Fill; 

	if(!parent || !data) return false;
	memcpy(&Line, defs.GetOutLine(), sizeof(LineDEF));
	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);
	UseRangeMark(data, 1, TmpTxt);
	if(!(Dlg = new DlgRoot(BarDlg, data)))return false;
	hDlg = CreateDlgWnd("Simple Bar Chart", 50, 50, 370, 280, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			break;
		case 1:
			if(rY) delete rY;
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)){
				rY = new AccRange(TmpTxt);
				yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
				}
			else {
				rY = 0L;		yRange = 0L;
				}
			if(!(n = rY ? rY->CountItems() : 0)) {
				res = -1;
				ErrorBox("Data range not valid.");
				}
			break;
			}
	} while(res < 0);
	if(res == 1 && n && rY) {
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
		Command(CMD_FLUSH, 0L, 0L);
		nPoints = n;
		Bars = (Bar**)calloc(nPoints, sizeof(Bar*));
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
		Dlg->GetValue(201, &start);	Dlg->GetValue(203, &step);
		if(step < 0.001) step = 1.0;
		Dlg->GetValue(205, &bw);
		if(bw < 5) bw = 60;
		ic = 0;
		x = start;
		if(Bars) do {
			if(data->GetValue(l, k, &y)){
				Bars[ic] = new Bar(this, data, x, y, BAR_VERTB | BAR_RELWIDTH, -1, -1, k, l);
				CheckBounds(x, y);
				x += step;
				ic++;
				}
			}while(rY->GetNext(&k, &l));
		if(ic){
			bRet = true;
			Command(CMD_BAR_FILL, &Fill, 0L);
			SetColor(COL_BAR_LINE, Line.color);
			SetSize(SIZE_BAR_LINE, Line.width);
			SetSize(SIZE_BAR, bw);
			BarDist.fx = step;
			}
		}
	if(rY) delete rY;
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Scatter plot properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
PlotScatt::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab2 = {22, 50, 10, "Layout"};
	TabSHEET tab3 = {50, 88, 10, "Error Bars"};
	TabSHEET tab4 = {88, 131, 10, "Data Labels"};
	char text1[100], text2[100], text3[100], text4[100];
	int icon = ICO_INFO;
	DlgInfo XYDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
		{6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
		{7, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
		{102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
		{103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 65, 100, 10},
		{104, 105, 0, 0x0L, ICON, (void*)&icon, 10, 85, 10, 10},
		{105, 106, 0, 0x0L, LTEXT, (void*)"Valid ranges include e.g. \'a1:g13\'", 30, 85, 30, 6},
		{106, 107, 0, 0x0L, LTEXT, (void*)"or \'b4:j4\' if data are available.", 30, 91, 30, 6},
		{107, 0, 0, 0x0L, LTEXT, (void*)"Separate multiple ranges by \' ; \'.", 30, 97, 30, 6},
		{200, 201, 0, 0x0L, CHECKBOX, (void*)" symbols", 25, 30, 60, 8},
		{201, 202, 250, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{202, 203, 255, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{203, 204, 0, 0x0L, CHECKBOX, (void*)" arrows", 25, 80, 60, 8},
		{204, 0, 0, 0x0L, CHECKBOX, (void*)" drop lines", 25, 90, 60, 8},
		{250, 251, 0, ISRADIO, CHECKBOX, (void*)" line", 25, 40, 60, 8},
		{251, 0, 0, ISRADIO, CHECKBOX, (void*)" polygon", 25, 70, 60, 8},
		{255, 256, 0, ISRADIO, CHECKBOX, (void*)" vertical bars", 25, 50, 60, 8},
		{256, 0, 0, ISRADIO, CHECKBOX, (void*)" horizontal bars", 25, 60, 60, 8},
		{300, 301, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{301, 302, 0, 0x0L, CHECKBOX, (void*)"draw error bars", 15, 28, 50, 8},
		{302, 303, 0, 0x0L, LTEXT, (void*)"style:", 35, 40, 20, 8},
		{303, 304, 0, 0x0L, LTEXT, (void*)"range for error data:", 15, 82, 60, 8},
		{304, 0, 0, 0x0L, RANGEINPUT, text3, 20, 93, 100, 10},
		{400, 401, 0, 0x0L, CHECKBOX, (void*)"add labels to data points", 15, 28, 50, 8},
		{401, 402, 0, 0x0L, LTEXT, (void*)"spread sheet range for labels:", 15, 40, 60, 8},
		{402, 0, 0, 0x0L, RANGEINPUT, text4, 20, 51, 100, 10},
		{500, 501, 0, TOUCHEXIT|CHECKED|ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl),60,40,20,20},
		{501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 80, 40, 20, 20},
		{502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 100, 40, 20, 20},
		{503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 60, 60, 20, 20},
		{504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 80, 60, 20, 20},
		{505, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 100, 60, 20, 20}};
	DlgRoot *Dlg;
	void *hDlg;
	int c, i, j, k, l, i1, j1, k1, l1, m, n, o, p, ic;
	int ErrType = 0, res, BarType, nVals, nTxt, nTime;
	double x, y, e;
	lfPOINT fp1, fp2;
	bool bRet = false, bLayout = false, bContinue = false, bValid;
	anyResult xRes, yRes;
	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
	AccRange *rX, *rY, *rE, *rL;

	if(!parent || !data) return false;
	if(Id == GO_BARCHART) return CreateBarChart();
	UseRangeMark(data, 1, text1, text2, text3, text4);
	rX = rY = rE = rL = 0L;
	if(!(Dlg = new DlgRoot(XYDlg, data)))return false;
#ifdef _WINDOWS
	for(i = 104; i <= 107; i++) Dlg->TextSize(i, 12);
#else
	for(i = 104; i <= 107; i++) Dlg->TextSize(i, 10);
#endif
	if(DefSel & 0x01)Dlg->SetCheck(200, 0L, true);		if(DefSel & 0x02)Dlg->SetCheck(250, 0L, true);
	if(DefSel & 0x04)Dlg->SetCheck(255, 0L, true);		if(DefSel & 0x08)Dlg->SetCheck(256, 0L, true);
	hDlg = CreateDlgWnd("XY Plot properties", 50, 50, 388, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 500:	case 501:	case 502:
		case 503:	case 504:	case 505:
			ErrType = res-500;
			Dlg->SetCheck(301, 0L, true);
			res = -1;
			break;
		case 4:								// the data tab sheet
			Dlg->Activate(101, true);	res = -1;				break;
		case 5:								// the layout tab sheet
			bLayout = true;				res = -1;				break;
		case 6:								// the error tab sheet
			Dlg->Activate(304, true);	res = -1;				break;
		case 7:								// the label tab sheet
			Dlg->Activate(402, true);	res = -1;				break;
		case 1:								// OK
			if(rX) delete rX;	if(rY) delete rY; if(rE) delete rE;
			rX = rY = rE = 0L;						// check x-range
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
			if(!(n = rX ? rX->CountItems() : 0)) {
				Dlg->SetCheck(4, 0L, true);
				res = -1;
				bContinue = true;
				ErrorBox("X-range not specified\nor not valid.");
				}
			else {							// check y-range
				if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
				if(n != (rY ? rY->CountItems() : 0)) {
					Dlg->SetCheck(4, 0L, true);
					res = -1;
					bContinue = true;
					ErrorBox("Y-range missing\nor not valid.\n"
						"Size must match X-range.");
					}
				}
			//check for error bar
			if(res >0 && Dlg->GetCheck(301)) {
				if(Dlg->GetText(304, TmpTxt, TMP_TXT_SIZE)) rE = new AccRange(TmpTxt);
				if(n != (rE ? rE->CountItems() : 0)) {
					Dlg->SetCheck(6, 0L, true);
					res = -1;
					bContinue = true;
					ErrorBox("Range for errors missing\nor not valid.\n"
						"Size must match X- and Y-range.");
					if(rE) delete (rE);
					rE = 0L;
					}
				}
			//check for data labels
			if(res >0 && Dlg->GetCheck(400)) {
				if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) rL = new AccRange(TmpTxt);
				if(n != (rL ? rL->CountItems() : 0)) {
					Dlg->SetCheck(7, 0L, true);
					res = -1;
					bContinue = true;
					ErrorBox("Range for labels missing\nor not valid.\n"
						"Size must match X- and Y-range.");
					if(rL) delete (rL);
					rL = 0L;
					}
				}
			//check if something left to do
			if(res > 0 && !rE && !rL && !Dlg->GetCheck(200) && !Dlg->GetCheck(250) && 
				!Dlg->GetCheck(251) && !Dlg->GetCheck(255) && !Dlg->GetCheck(256) && 
				!Dlg->GetCheck(203)) {
				Dlg->SetCheck(5, 0L, true);
				res = -1;
				bContinue = true;
				ErrorBox("Nothing to do!\nSelect at least one item.");
				}
			//the layout menu must have been visited
			if(res > 0 && !bLayout){
				Dlg->SetCheck(5, 0L, bLayout = true);
				res = -1;
				}
			break;
			}
		}while (res <0);
	if(res == 1 && n && rX && rY){				//OK pressed
		Command(CMD_FLUSH, 0L, 0L);
		nPoints = n;
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		data_desc = rY->RangeDesc(data, 1);
		//analyse data types
		if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
			if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
			else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
			}
		if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
			if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
			else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
			}
		//Create graphic objects
		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
		i1 = i;	j1 = j;	k1 = k;	l1 = l;
		ic = c = 0;
		if(Dlg->GetCheck(200)) Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*));
		if((BarType = Dlg->GetCheck(255) ? BAR_VERTB : Dlg->GetCheck(256) ? BAR_HORL : 0))
			Bars = (Bar**)calloc(nPoints, sizeof(Bar*));
		BarType |= BAR_RELWIDTH;
		if(Dlg->GetCheck(204)) DropLines = (DropLine**)calloc(nPoints, sizeof(DropLine*));
		if(Dlg->GetCheck(203)) Arrows = (Arrow**)calloc(nPoints, sizeof(Arrow*));
		if(Dlg->GetCheck(301) && rE) {					//error bars ?
			Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
			if(Dlg->GetText(304, TmpTxt, TMP_TXT_SIZE)){
				ErrRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
				rE->GetFirst(&m, &n);	rE->GetNext(&m, &n);
				}
			else {
				rE = 0L;		ErrRange = 0L;
				}
			}
		if(Dlg->GetCheck(400) && rL) {					//labels ?
			Labels = (Label**)calloc(nPoints, sizeof(Label*));
			if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) LbRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
			rL->GetFirst(&o, &p);	rL->GetNext(&o, &p);
			}
		if(Dlg->GetCheck(250) && nPoints >1) TheLine = new DataLine(this, data, xRange, yRange); 
		else if(Dlg->GetCheck(251) && nPoints >2) TheLine = new DataPolygon(this, data, xRange, yRange); 
		do {
			bValid = false;
			if(data->GetResult(&xRes, j, i, false) && data->GetResult(&yRes, l, k, false)) {
				bValid = true;
				if(x_tv) {
					if(xRes.type == ET_TEXT) x = x_tv->GetValue(xRes.text);
					else bValid = false;
					}
				else if(x_dtype == ET_DATETIME) {
					if(xRes.type == ET_DATE || xRes.type == ET_TIME  || xRes.type == ET_DATETIME) x = xRes.value;
					else bValid = false;
					}
				else {
					if(xRes.type == ET_VALUE) x = xRes.value;
					else bValid = false;
					}
				if(y_tv) {
					if(yRes.type == ET_TEXT) y = y_tv->GetValue(yRes.text);
					else bValid = false;
					}
				else if(y_dtype == ET_DATETIME) {
					if(yRes.type == ET_DATE || yRes.type == ET_TIME  || yRes.type == ET_DATETIME) y = yRes.value;
					else bValid = false;
					}
				else {
					if(yRes.type == ET_VALUE) y = yRes.value;
					else bValid = false;
					}
				}
			if(bValid){
				if(Symbols && (Symbols[ic] = new Symbol(this, data, x, y, DefSym, i, j, k, l))){
					Symbols[ic]->idx = c;
					}
				if(Bars)Bars[ic] = new Bar(this, data, x, y, BarType, i, j, k, l);
				if(DropLines) DropLines[ic] = new DropLine(this, data, x, y, 
					DL_YAXIS | DL_XAXIS, i, j, k, l);
				if(Arrows) {
					if(ic){
						fp1.fx = fp2.fx;	fp1.fy = fp2.fy;
						}
					else {
						fp1.fx = x;			fp1.fy = y;
						}
					fp2.fx = x;			fp2.fy = y;
					Arrows[ic] = new Arrow(this, data, ic ? fp1 : fp2, fp2, ARROW_LINE,
						i1, j1, k1, l1, i, j, k, l);
					//the first arrow has zero length
					//all other arrows conncect to the following point
					i1 = i;	j1 = j;	k1 = k;	l1 = l;
					}
				if(Labels && rL) {
					if(data->GetText(p, o, TmpTxt, TMP_TXT_SIZE)) 
						Labels[ic] = new Label(this, data, x, y, &lbdef, 
							LB_X_DATA | LB_Y_DATA, i, j, k, l, o, p);
					rL->GetNext(&o, &p);
					}
				if(Errors && rE){
					if(data->GetValue(n, m, &e))
						Errors[ic]= new ErrorBar(this, data, x, y, e, ErrType,
						i, j, k, l, m, n);
					rE->GetNext(&m, &n);
					}
				else CheckBounds(x, y);
				ic++;
				}
			else {
				if(Labels && rL) rL->GetNext(&o, &p);
				if(Errors && rE) rE->GetNext(&m, &n);
				}
			c++;
			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
		if(ic) bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;	if(rY) delete rY;	if(rE) delete rE;	if(rL) delete rL;
	return (dirty = bRet);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// calculate means and error to create a xy-plot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
xyStat::PropertyDlg()
{
	char text1[100], text2[100];
	DlgInfo StatDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
		{2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
		{10, 100, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"range for grouping variable", 10, 10, 90, 9},
		{101, 102, 0, 0x0L, LTEXT, (void*)"(X data)", 10, 20, 60, 9},
		{102, 103, 0, 0x0L, RANGEINPUT, text1, 10, 30, 100, 10},
		{103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 45, 90, 9},
		{104, 200, 0, 0x0L, RANGEINPUT, text2, 10, 55, 100, 10},
		{200, 300, 201, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 75, 165, 50},
		{201, 202, 0, CHECKED, CHECKBOX, (void*)" line", 15, 80, 50, 9},
		{202, 203, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 90, 50, 9},
		{203, 204, 0, 0x0L, CHECKBOX, (void*)" bars", 15, 100, 50, 9},
		{204, 205, 0, 0x0L, LTEXT, (void*)"using", 65, 90, 30, 9},
		{205, 206, 0, CHECKED, RADIO1, (void*)" arithmetic mean", 95, 80, 50, 9},
		{206, 207, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 90, 50, 9},
		{207, 208, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 100, 50, 9},
		{208, 0, 0, 0x0L, RADIO1, (void*)" median", 95, 110, 50, 9},
		{300, 400, 301, ISPARENT | CHECKED, GROUPBOX, (void*) " draw error bars ", 10, 130, 165, 40},
		{301, 302, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" std. deviation (SD)", 15, 135, 70, 9},
		{302, 303, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 145, 70, 9},
		{303, 304, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 135, 70, 9},
		{304, 305, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 145, 70, 9},
		{305, 306, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 155, 70, 9},
		{306, 307, 0, 0x0L, EDVAL1, &ci, 28, 154, 15, 10},
		{307, 0, 0, 0x0L, LTEXT, (void*) "%  conf. interval", 45, 155, 70, 9},
		{400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 175, 165, 30},
		{401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 180, 70, 9},
		{402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 180, 70, 9},
		{403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 190, 24, 9},
		{404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 189, 30, 10}};
	DlgRoot *Dlg;
	void *hDlg;
	bool bRet = false;
	int i, res, width, height, cb_mdesc;
	double x, y, e, f, dx, dy;
	lfPOINT fp1, fp2;
	char errdesc[40], *mdesc;
	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};

	if(!parent || !data) return false;
	UseRangeMark(data, 1, text1, text2);
	if(!(Dlg = new DlgRoot(StatDlg, data)))return false;
	text1[0] = text2[0] = 0;
	hDlg = CreateDlgWnd("Mean and Error Plot", 50, 50, 370, 450, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(Dlg->GetCheck(10)) res=-1;
			break;
		case 1:
			if(!(Dlg->GetText(102, text1, 100) && Dlg->GetText(104, text2, 100) && text1[0] && text2[0])) res = 2;
			break;
			}
		}while (res <0);
	if(res == 1) {
		xRange = (char*)memdup(text1, ((int)strlen(text1))+2, 0);
		yRange = (char*)memdup(text2, ((int)strlen(text2))+2, 0);
		type = 0;
		if(Dlg->GetCheck(201)) type |= 0x0001;		if(Dlg->GetCheck(202)) type |= 0x0002;
		if(Dlg->GetCheck(203)) type |= 0x0004;
		if(Dlg->GetCheck(205)) type |= 0x0010;		if(Dlg->GetCheck(206)) type |= 0x0020;
		if(Dlg->GetCheck(207)) type |= 0x0040;		if(Dlg->GetCheck(208)) type |= 0x0080;
		if(Dlg->GetCheck(301)) type |= 0x0100;		if(Dlg->GetCheck(302)) type |= 0x0200;
		if(Dlg->GetCheck(303)) type |= 0x0400;		if(Dlg->GetCheck(304)) type |= 0x0800;
		if(Dlg->GetCheck(305)) type |= 0x1000;
		if(Dlg->GetCheck(401)) type |= 0x2000;		if(Dlg->GetCheck(402)) type |= 0x4000;
		Dlg->GetValue(306, &ci);					TmpTxt[0] = 0;
		if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		CreateData();
		if(type && curr_data) {
			switch (type & 0x00f0) {
				case 0x0010:		mdesc = "Mean";					break;
				case 0x0020:		mdesc = "Geometric mean";		break;
				case 0x0040:		mdesc = "Harmonic mean";		break;
				case 0x0080:		mdesc = "Median";				break;
				default:			mdesc = "n.a.";					break;
				}
			cb_mdesc = (int)strlen(mdesc);
			curr_data->GetSize(&width, &height);		nPoints = height;
#ifdef USE_WIN_SECURE
			sprintf_s(text1, 100, "a1:a%d", height);	sprintf_s(text2, 100, "b1:b%d", height);
#else
			sprintf(text1, "a1:a%d", height);			sprintf(text2, "b1:b%d", height);
#endif
			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
			if(type & 0x0001) {
				if(nPoints >1 && (TheLine = new DataLine(this, curr_data, text1, text2)) &&
					(TheLine->name = (char*)malloc(cb_mdesc+2))) rlp_strcpy(TheLine->name, cb_mdesc+2, mdesc);
				}
			if((type & 0x0002) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
				for(i = 0; i < height; i++) {
					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
						&& (Symbols[i] = new Symbol(this, curr_data, x, y, DefSym, 0, i, 1, i))){
						Symbols[i]->idx = i;
						if(Symbols[i]->name = (char*)malloc(cb_mdesc+2))
							rlp_strcpy(Symbols[i]->name, cb_mdesc+2, mdesc);
						}
					}
				}
			if((type & 0x0004) && (Bars = (Bar**)calloc(nPoints, sizeof(Bar*)))) {
				for(i = 0; i < height; i++) {
					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
						&& (Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i))){
						if(Bars[i]->name = (char*)malloc(cb_mdesc+2))
							rlp_strcpy(Bars[i]->name, cb_mdesc+2, mdesc);
						}
					}
				}
			if(type & 0x1f00) {
				Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
				switch(type & 0x1f00) {
				case 0x0100:	rlp_strcpy(errdesc, 40, "Std. Dev.");			break;
				case 0x0200:	rlp_strcpy(errdesc, 40, "Std. Err.");			break;
				case 0x0400:	rlp_strcpy(errdesc, 40, "25, 75% Perc.");		break;
				case 0x0800:	rlp_strcpy(errdesc, 40, "Min./Max.");			break;
#ifdef USE_WIN_SECURE
				case 0x1000:	sprintf_s(errdesc, 40, "'%g%% CI", ci);			break;
#else
				case 0x1000:	sprintf(errdesc, "'%g%% CI", ci);				break;
#endif
				default:		rlp_strcpy(errdesc, 40, "error");
					}
				}
			if((type & 0x1300) && Errors) {
				for(i = 0; i < height; i++) {
					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
						&& curr_data->GetValue(i, 2, &e)) {
						Errors[i]= new ErrorBar(this, curr_data, x, y, e, 0, 0, i, 1, i, 2, i);
						if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
						}
					}
				}
			if((type & 0x0c00) && Errors) {
				for(i = 0; i < height; i++) {
					if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &e) && curr_data->GetValue(i, 3, &f)){
						fp1.fx = fp2.fx = x;	fp1.fy = e;		fp2.fy = f;
						Errors[i]= (ErrorBar*)new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 2, i, 0, i, 3, i);
						if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
						}
					}
				}
			if((type & 0x6000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
				dy = -0.4 * DefSize(SIZE_SYMBOL);
				if(type & 0x2000){
					lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
					dx = 0.0;
					}
				else {
					lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
					dx = -dy;
					}
				for(i = 0; i < height; i++) {
					if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 5, TmpTxt, TMP_TXT_SIZE, false)){
						if((type & 0x2000) && curr_data->GetValue(i, 4, &y)) 
							Labels[i] = new Label(this, curr_data, x, y, &lbdef, 
							LB_X_DATA | LB_Y_DATA, 0, i, 4, i, 5, i);
						else if((type & 0x4000) && curr_data->GetValue(i, 1, &y)) 
							Labels[i] = new Label(this, curr_data, x, y, &lbdef, 
							LB_X_DATA | LB_Y_DATA, 0, i, 1, i, 5, i);
						if(Labels[i]){
							Labels[i]->SetSize(SIZE_LB_YDIST, dy);
							Labels[i]->SetSize(SIZE_LB_XDIST, dx);
							}
						}
					}
				}
			Command(CMD_AUTOSCALE, 0L, 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Frequency distribution
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *FreqDlg_Tmpl =
	"1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
	"2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,153\n"
	"5,10,200,ISPARENT,SHEET,2,5,10,120,153\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"100,101,,,LTEXT,3,10,25,60,8\n"
	"101,102,,,RANGEINPUT,-15,10,38,110,10\n"
	"102,103,120,ISPARENT | CHECKED,GROUPBOX,4,10,55,110,42\n"
	"103,,150,ISPARENT | CHECKED,GROUPBOX,5,10,102,110,57\n" 
	"120,121,,CHECKED,RADIO1,6,15,60,30,9\n"
	"121,122,,, EDVAL1,7,47,60,15,10\n"
	"122,123,,, LTEXT,8,64,60,35,8\n"
	"123,124,,, RADIO1,9, 15, 72, 45, 9\n"
	"124,125,,, EDTEXT,-16,65,72,50,10\n"
	"125,126,,, RTEXT,10,15,84, 47,8\n"
	"126,,,,EDTEXT,-16,65,84,50,10\n"
	"150,151,,ISRADIO,CHECKBOX,13,15,107,30, 8\n"
	"151,152,,ISRADIO,CHECKBOX,14,15,117,30, 8\n"
	"152,153,,ISRADIO,CHECKBOX,15,65,107,30, 8\n"
	"153,154,,ISRADIO,CHECKBOX,16,65,117,30,8\n"
	"154,155,,ISRADIO,CHECKBOX,17,15,127,30,8\n"
	"155,156,,ISRADIO,CHECKBOX,18,15,137,30,8\n"
	"156,,,ISRADIO,CHECKBOX,19,15,147,30,8\n"
	"200,, 210,ISPARENT | CHECKED,GROUPBOX,11,10,27,110,61\n" 
	"210,,,LASTOBJ | NOSELECT,ODBUTTON,12,25,34,90,50";

bool
FreqDist::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 52, 10, "Style"};
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"spread sheet range for values",
		(void*)" classes ", (void*)" plot distribution ", (void*)"create", (void*)&step,
		(void*)"classes and bars", (void*)"class size is", (void*)"starting at",
		(void*)" bar style ", (void*)OD_filldef, (void*)" normal", (void*)" log-normal",
		(void*)" binomial", (void*)" poisson", (void*)" exponential", (void*)" rectangular",
		(void*)" chi-square"};
	DlgInfo *FreqDlg;
	DlgRoot *Dlg;
	void *hDlg;
	bool bRet = false;
	int res, r, c;
	double tmp;
	char *mrk;
	AccRange *aR;

	if(!parent || !data) return false;
	if(!(FreqDlg = CompileDialog(FreqDlg_Tmpl, dyndata))) return false;
	step = 7;	TmpTxt[100] = 0;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
	if(data->Command(CMD_GETMARK, &mrk, 0L)) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
	else TmpTxt[0] = 0;
	if(!(Dlg = new DlgRoot(FreqDlg, data)))return false;
	hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 370, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(Dlg->GetCheck(10)) res=-1;
			break;
		case 1:
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssRef = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
			if(Dlg->GetCheck(150)) type = 1;
			else if(Dlg->GetCheck(151)) type = 2;
			else if(Dlg->GetCheck(154)) type = 3;
			else if(Dlg->GetCheck(155)) type = 4;
			else if(Dlg->GetCheck(156)) type = 5;
			else if(Dlg->GetCheck(152)) type = 10;
			else if(Dlg->GetCheck(153)) type = 11;
			else type = 0;
			break;
			}
		}while (res <0);
	if(res==1 && (plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*)))) {
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
		BarFill.hatch = &HatchLine;
		if(Dlg->GetCheck(123) && Dlg->GetValue(124, &step) && Dlg->GetValue(126, &start)) ProcData(-2);
		else {
			Dlg->GetValue(121, &step);		ProcData(-1);
			}
		if(y_info = (char*)malloc(25*sizeof(char))) rlp_strcpy(y_info, 25, "No. of observations");
		if(x_info = (char*)malloc(25*sizeof(char))){
			rlp_strcpy(x_info, 25, "Categories");
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && (aR = new AccRange(TmpTxt))) {
				if(aR->GetFirst(&c, &r) && !data->GetValue(r, c, &tmp) && data->GetText(r, c, TmpTxt, 150, false))
					rlp_strcpy(x_info, 25, TmpTxt);
				delete aR;
				}
			}
		if(plots[0]) bRet = true;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(FreqDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Regression properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char* RegDlg_Tmpl = 
	"1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
	".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,130,85\n"
	".,10,200,ISPARENT,SHEET,2,5,10,130,85\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"100,+,,,LTEXT,3,10,22,60,8\n"
	".,.,,,RANGEINPUT,-16,20,32,100,10\n"
	".,.,,,LTEXT,4,10,45,60,8\n"
	".,.,,,RANGEINPUT,-17,20,55,100,10\n"
	".,.,,CHECKED,CHECKBOX,5,10,70,100,8\n"
	".,,,,CHECKBOX,6,10,80,100,8\n" 
	"200,210,201,CHECKED | ISPARENT, GROUPBOX,7,10,30,58,56\n"
	"201,+,,CHECKED, RADIO1,8,20,40,30,8\n"
	".,.,,,RADIO1,9,20,50,30,8\n"
	".,.,,,RADIO1,10,20,60,30,8\n"
	".,,,,RADIO1,11,20,70,30,8\n"
	"210,,211,CHECKED | ISPARENT,GROUPBOX,12,72,30,58,56\n"
	".,+,,CHECKED,RADIO1,13,82,40,30,8\n"
	".,.,,,RADIO1,14,82,50,30,8\n"
	".,.,,,RADIO1,15,82,60,30,8\n"
	".,,,LASTOBJ,RADIO1,16,82,70,30,8";

bool
Regression::PropertyDlg()
{
	TabSHEET tab1 = {0, 28, 10, "Data"};
	TabSHEET tab2 = {28, 70, 10, "Transform"};
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"range for X Data",
		(void*)"range for Y Data", (void*)" include symbols in plot", (void*) " draw SD ellipse",
		(void*)"  x-values  ", (void*)"x = x", (void*)"x = log(x)", (void*)"x = 1/x",
		(void*)"x = sqrt(x)", (void*)"  y-values  ", (void*)"y = y", (void*)"y = log(y)",
		(void*)"y = 1/y",(void*)"y = sqrt(y)"};
	DlgInfo *RegDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int c, i, j, k, l, ic, res, n;
	double x, y;
	AccRange *rX, *rY;
	bool bRet = false, bContinue = false, dValid;
	lfPOINT *values = 0L;

	if(!parent || !data) return false;
	if(!(RegDlg = CompileDialog(RegDlg_Tmpl, dyndata))) return false;
	rX = rY = 0L;
	UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200);
	if(!(Dlg = new DlgRoot(RegDlg, data)))return false;
	hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 230, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 1:								// OK
			if(rX) delete rX;	if(rY) delete rY;
			rX = rY = 0L;						// check x-range
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
			if(!(n = rX ? rX->CountItems() : 0)) {
				Dlg->SetCheck(4, 0L, true);
				res = -1;
				bContinue = true;
				ErrorBox("X-range not specified\nor not valid.");
				}
			else {							// check y-range
				if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
				if(n != (rY ? rY->CountItems() : 0)) {
					res = -1;
					bContinue = true;
					ErrorBox("Y-range missing\nor not valid.\n"
						"Size must match X-range.");
					}
				}
			}
		}while (res <0);
	if(res==1 && n && rX && rY && (values =(lfPOINT*)calloc(nPoints=n, sizeof(lfPOINT)))){				//OK pressed
		Command(CMD_FLUSH, 0L, 0L);
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
		if(Dlg->GetCheck(202)) type = 0x100;
		else if(Dlg->GetCheck(203)) type = 0x200;
		else if(Dlg->GetCheck(204)) type = 0x300;
		if(Dlg->GetCheck(212)) type |= 0x1000;
		else if(Dlg->GetCheck(213)) type |= 0x2000;
		else if(Dlg->GetCheck(214)) type |= 0x3000;
		ic = c = 0;
		if(Dlg->GetCheck(104)) Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*));
		do {
			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
				dValid = true;
				switch(type & 0x700) {
				case 0x100:					//logarithmic x
					if(dValid = x > defs.min4log) values[ic].fx = log10(x);
					break;
				case 0x200:					//reciprocal x
					if(dValid = fabs(x) >defs.min4log) values[ic].fx = 1.0/x;
					break;
				case 0x300:					//square root x
					if(dValid = fabs(x) >defs.min4log) values[ic].fx = sqrt(x);
					break;
				default:	values[ic].fx = x;	break;		//linear x
					}
				if(dValid) switch(type & 0x7000) {
				case 0x1000:				//logarithmic y
					if(dValid = y > defs.min4log) values[ic].fy = log10(y);
					break;
				case 0x2000:				//reciprocal y
					if(dValid = fabs(y) > defs.min4log) values[ic].fy = 1.0/y;
					break;
				case 0x3000:				//square root y
					if(dValid = fabs(y) > defs.min4log) values[ic].fy = sqrt(y);
					break;
				default:	values[ic].fy = y;	break;		//linear y
					}
				if(dValid && Symbols && (Symbols[ic] = new Symbol(this, data, x, y, 
					SYM_CIRCLE, i, j, k, l))){
					Symbols[ic]->idx = c;
					}
				if(dValid) {
					CheckBounds(x, y);
					ic++;
					}
				}
			c++;
			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
		if(ic) {
			if(Dlg->GetCheck(105) && (sde = new SDellipse(this, data, values, ic, type | 0x20002))&&
				(bRet= sde->Command(CMD_INIT, 0L, 0L)))sde->Command(CMD_BOUNDS, &Bounds, 0L);
			else if((rLine = new RegLine(this, data, values, ic, type)) && 
				(bRet= rLine->PropertyDlg()))rLine->Command(CMD_BOUNDS, &Bounds, 0L);
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;	if(rY) delete rY;
	free(RegDlg);		if(values) free(values);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bubble plot properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *BubPlotDlg_Tmpl = 
	"1, 2, 0, DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
	"2, 3, 0, 0x0L, PUSHBUTTON,-2,148,25,45,12\n"
	"3, 500, 4, ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4, 5, 100, ISPARENT | CHECKED,SHEET,1,5,10,130,120\n"
	"5, 6, 200, ISPARENT, SHEET,2,5,10,130,120\n"
	"6, 10, 300, ISPARENT, SHEET,3,5,10,130,120\n"
	"10,,, CHECKED,CHECKPIN,0,5,0,12,8\n"
	"100,+,,,LTEXT,4,10,40,60,8\n"
	".,.,,,RANGEINPUT,-15,20,50,100,10\n"
	".,.,,,LTEXT,5,10,65,60,8\n"
	".,.,,,RANGEINPUT,-16,20,75,100,10\n"
	".,.,,,LTEXT,6,10,90,60,8\n"
	".,,,,RANGEINPUT,-17,20,100,100,10\n"
	"200,+,,,LTEXT,-27,10,30,110,8\n"
	".,.,,ISRADIO | CHECKED,ODBUTTON,7,30,40,20,20\n"
	".,.,,ISRADIO,ODBUTTON,7,50,40,20,20\n"
	".,.,,ISRADIO,ODBUTTON,7,70,40,20,20\n"
	".,.,,ISRADIO,ODBUTTON,7,90,40,20,20\n"
	".,.,,,LTEXT,8,7,67,45,8\n"
	".,.,,,RTEXT,9,7,75,20,8\n"
	".,.,,OWNDIALOG,COLBUTT,10,29,75,25,10\n"
	".,.,,,RTEXT,11,67,75,20,8\n"
	".,.,,,EDVAL1,12,88,75,25,10\n"
	".,.,,,LTEXT,-3,114,75,15,8\n"
	".,.,,,LTEXT,13,7,97,45,8\n"
	".,.,,,RTEXT,-11,7,105,20,8\n"
	".,.,,TOUCHEXIT | OWNDIALOG,COLBUTT,14,29,105,25,10\n"
	".,.,,,RTEXT,15,67,105,20,8\n"
	".,,,TOUCHEXIT | OWNDIALOG,FILLBUTTON,16,88,105,25,10\n"
	"300,+,,,LTEXT,17,10,30,110,8\n"
	".,.,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,,,LTEXT,18,10,75,110,8\n"
	".,,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"400,+,,CHECKED,RADIO1,-3,40,40,45,8\n"
	".,.,,,RADIO1,19,40,50,45,8\n"
	".,,,,RADIO1,20,40,60,45,8\n"
	"410,+,,CHECKED,RADIO1,21,40,85,45,8\n"
	".,.,,,RADIO1,22,40,95,45,8\n"
	".,,,LASTOBJ,RADIO1,23,40,105,45,8";
bool
BubblePlot::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 57, 10, "Layout"};
	TabSHEET tab3 = {57, 90, 10, "Scaling"};
	int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
	FillDEF ShowFill;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for X Data",
		(void*)"range for Y Data", (void*)"range for sizes", (void*)OD_BubbleTempl,
		(void*)"outline:", (void*)"color", (void *)&BubbleLine.color, (void*)"line width",
		(void*)&BubbleLine.width, (void*)"fill:", (void *)&BubbleFill.color, (void*)"pattern",
		(void *)&ShowFill, (void*)"sizes are given as", (void*)"proportionality (relative to circle)",
		(void*)"scaling with X axis", (void*)"scaling with Y axis", (void*)"diameter",
		(void*)"circumference", (void*)"area"};
	DlgInfo *PlotDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, k, l, m, n, ic, res, BubbleType;
	double x, y, s;
	double tmp;
	bool bRetVal = false, bFillChanged, bContinue = false;
	AccRange *rX, *rY, *rS;
	LineDEF ShowFillLine ={0.2f, 1.0f, 0x0L, 0x0L};

	if(!parent || !data) return false;
	if(!(PlotDlg = CompileDialog(BubPlotDlg_Tmpl, dyndata))) return false;
	UseRangeMark(data, 1, TmpTxt, TmpTxt+100, TmpTxt+200);
	memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
	if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
	ShowFill.hatch = &ShowFillLine;
	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
	hDlg = CreateDlgWnd("Create Bubble Plot", 50, 50, 400, 300, Dlg, 0x4L);
	rX = rY = rS = 0L;
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 213:					//fillcolor changed
			Dlg->GetColor(213, &ShowFill.color);
			Dlg->DoPlot(NULL);
			res = -1;
			break;
		case 215:					//copy color from pattern dialog
			Dlg->SetColor(213, ShowFill.color);
			bFillChanged = true;
			res = -1;
			break;
		case 1:						//OK button
			if(Dlg->GetText(101, TmpTxt, 100) && Dlg->GetText(103, TmpTxt+100, 100) && 
				Dlg->GetText(105, TmpTxt+200, 100) && (rX = new AccRange(TmpTxt)) &&
				(rY = new AccRange(TmpTxt+100)) && (rS = new AccRange(TmpTxt+200))) {
				if((i = rX->CountItems()) == rY->CountItems() && i == rS->CountItems()){
					// OK pressed and ranges checked: exit loop and process data
					}
				else {
					if(rX) delete (rX);	if(rY) delete (rY);	if(rS) delete (rS);
					rX = rY = rS = 0L;
					ErrorBox("Ranges must be of equal size");
					Dlg->SetCheck(4, 0L, bContinue = true);
					res = -1;
					}
				}
			else res = -1;				//continue with dialog if error
			}
		}while (res <0);
	if(res ==1 && rX && rY && rS && (nPoints = rX->CountItems()) && 
		(Bubbles = (Bubble**)calloc(nPoints, sizeof(Bubble*)))) {
		//accept settings and create bubbles for plot
		if(Dlg->GetCheck(202)) BubbleType = BUBBLE_SQUARE;
		else if(Dlg->GetCheck(203)) BubbleType = BUBBLE_UPTRIA;
		else if(Dlg->GetCheck(204)) BubbleType = BUBBLE_DOWNTRIA;
		else BubbleType = BUBBLE_CIRCLE;
		if(Dlg->GetCheck(401)) BubbleType |= BUBBLE_XAXIS;
		else if(Dlg->GetCheck(402)) BubbleType |= BUBBLE_YAXIS;
		if(Dlg->GetCheck(411)) BubbleType |= BUBBLE_CIRCUM;
		else if(Dlg->GetCheck(412)) BubbleType |= BUBBLE_AREA;
		if(Dlg->GetValue(209, &tmp)) BubbleLine.width = (float)tmp;
		Dlg->GetColor(207, &BubbleLine.color);		Dlg->GetColor(213, &BubbleFill.color);
		rX->GetFirst(&i, &j);		rY->GetFirst(&k, &l);	rS->GetFirst(&m, &n);
		rX->GetNext(&i, &j);		rY->GetNext(&k, &l);	rS->GetNext(&m, &n);
		ic = 0;
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		if(Bubbles) do {
			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &s)){
				CheckBounds(x, y);
				Bubbles[ic++] = new Bubble(this, data, x, y, s, BubbleType, &ShowFill, 
					&BubbleLine, i, j, k, l, m, n);
				}
			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rS->GetNext(&m, &n));
		bRetVal = ic >0;
		}
	CloseDlgWnd(hDlg);
	if(rX) delete (rX);		if(rY) delete (rY);		if(rS) delete (rS);
	delete Dlg;			free(PlotDlg);			return bRetVal;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polar plot properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *AddPolDlg_Tmpl = 
	"1,2,,DEFAULT,PUSHBUTTON,-1,140,14,45,12\n"
	"2,3,,,PUSHBUTTON,-2,140,29,45,12\n"
	"3,10,200,ISPARENT | CHECKED,GROUPBOX,1,5,14,131,96\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"200,201,,CHECKED | EXRADIO,ODBUTTON,2,10,24,20,20\n"
	"201,202,,EXRADIO,ODBUTTON,2,30,24,20,20\n"
	"202,203,,EXRADIO,ODBUTTON,2,50,24,20,20\n"
	"203,204,,EXRADIO,ODBUTTON,2,70,24,20,20\n"
	"204,210,,EXRADIO,ODBUTTON,2,90,24,20,20\n"
	"210,211,,,LTEXT,3,10,50,50,8\n"
	"211,212,,,RANGEINPUT,-15,20,62,100,10\n"
	"212,213,,,LTEXT,4,10,75,50,8\n"
	"213,,,LASTOBJ,RANGEINPUT,-16,20,87,100,10";

bool
PolarPlot::AddPlot()
{
	void *dyndata[] = {(void*)" select template and data range ", (void*)OD_PolarTempl,
		(void*)"range for x-data (circular or angular data)",
		(void*)"range for y-data (radial data)"};
	DlgInfo *PolDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, k, l, ic, n, res, cType = 200;
	bool bRet = false, bContinue = false;
	double x, y;
	AccRange *rX = 0L, *rY = 0L;
	Symbol **Symbols = 0L;
	DataLine *TheLine = 0L;
	Plot **tmpPlots;
	Function *func;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent || !data) return false;
	if(!(PolDlg = CompileDialog(AddPolDlg_Tmpl, dyndata))) return false;
	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
	if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
	Dlg->bModal = false;
	hDlg = CreateDlgWnd("Add Polar Plot", 50, 50, 388, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 200: case 201:	case 202:	case 203:	case 204:
			if(res == 204) {
				Dlg->Activate(211, false);			Dlg->Activate(213, false);
				}
			else if(cType == 204) {
				Dlg->Activate(211, true);			Dlg->Activate(213, true);
				}
			if(res == cType) res = 1;
			else {
				cType = res;
				res = -1;
				}
			break;
			}
		}while (res <0);
	if(res == 1 && Dlg->GetText(211, TmpTxt, 100) && Dlg->GetText(213, TmpTxt+100, 100) && 
		(rX = new AccRange(TmpTxt)) && (rY = new AccRange(TmpTxt+100)) &&
		(n = rX ? rX->CountItems() : 0) && 
		(tmpPlots = (Plot**)realloc(Plots, (nPlots+2)*sizeof(Plot*)))) {
		Undo.SetDisp(cdisp);
		Plots = tmpPlots;
		if(Dlg->GetCheck(200) || Dlg->GetCheck(201)) 
			Symbols = (Symbol**) calloc(n+1, sizeof(Symbol*));
		if(Dlg->GetCheck(201) || Dlg->GetCheck(202)) 
			TheLine = new DataLine(this, data, TmpTxt, TmpTxt+100);
		else if(Dlg->GetCheck(203))
			TheLine = new DataPolygon(this, data, TmpTxt, TmpTxt+100);
		else if(Dlg->GetCheck(204)) {
			if(func = new Function(this, data, "Function")){
				if(bRet = func->PropertyDlg()){
					Undo.SetGO(this, (GraphObj**) &Plots[nPlots++], func, 0L);
					memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
					}
				else DeleteGO(func);
				}
			}
		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
		ic = 0;
		if(Symbols || TheLine) {
			do {
				if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
					CheckBounds(y, y);
					if(Symbols)Symbols[ic++] = new Symbol(this,data,x,y,SYM_CIRCLE,i,j,k,l);
					}
				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
			Undo.SetGO(this, (GraphObj**) &Plots[nPlots++], 
				new PlotScatt(this, data, ic, Symbols, TheLine), 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;			free(PolDlg);
	if(rX) delete rX;	if(rY) delete rY;
	return bRet;
}

bool
PolarPlot::Config()
{
	TabSHEET tab1 = {0, 40, 10, "Plot"};
	DlgInfo PPDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 102, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 102, 25, 45, 12},
		{3, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 90},
		{100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
		{101, 0, 0, LASTOBJ, CHECKBOX, (void*)"show radial axis", 15, 85, 60, 9}};
	DlgRoot *Dlg;
	void *hDlg;
	int res;
	bool bRet = false;
	LineDEF OutLine;

	memcpy(&OutLine, defs.GetOutLine(), sizeof(LineDEF));
	if(Axes && Axes[0]) {
		OutLine.color = Axes[0]->GetColor(COL_AXIS);
		OutLine.width = Axes[0]->GetSize(SIZE_AXIS_LINE);
		}
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&OutLine, 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
	Dlg = new DlgRoot(PPDlg, data);
	if(!(type & 0x01))Dlg->SetCheck(101, 0L, true);
	hDlg = CreateDlgWnd("Polar Plot properties", 50, 50, 310, 234, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		}while (res < 0);
	if(res == 1){						//OK pressed
		if(Dlg->GetCheck(101)) type &= ~0x01;
		else type |= 0x01;
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&OutLine, 0);
		if(Axes && Axes[0]) {
			Axes[0]->SetColor(COL_AXIS, OutLine.color);
			Axes[0]->SetSize(SIZE_AXIS_LINE, OutLine.width);
			}
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
		Fill.hatch = &FillLine;
		bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

bool
PolarPlot::PropertyDlg()
{
	TabSHEET tab1 = {0, 45, 10, "Coordinates"};
	TabSHEET tab2 = {45, 70, 10, "Type"};
	char text1[100], text2[100];
	double lox = 0.0, hix = 360.0, fcx =10.0, fcy = 20.0, frad=40.0;
	DlgInfo PolDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
		{3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT | TOUCHEXIT, SHEET, &tab1, 5, 10, 131, 100},
		{5, 10, 200, ISPARENT | TOUCHEXIT | CHECKED, SHEET, &tab2, 5, 10, 131, 100},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"angular range (full circle)", 10, 25, 60, 8},
		{101, 102, 0, 0x0L, RTEXT, (void*)"min =", 5, 37, 25, 8},
		{102, 103, 0, 0x0L, EDVAL1, &lox, 30, 37, 30, 10},
		{103, 104, 0, 0x0L, RTEXT, (void*)"max =", 60, 37, 25, 8},
		{104, 105, 0, 0x0L, EDVAL1, &hix, 85, 37, 30, 10},
		{105, 106, 0, 0x0L, RTEXT, (void*)"angular offset:", 10, 49, 50, 8},
		{106, 107, 0, 0x0L, EDVAL1, &offs, 62, 49, 30, 10},
		{107, 108, 0, 0x0L, LTEXT, (void*)"position of center:", 10, 65, 40, 8},
		{108, 109, 0, 0x0L, RTEXT, (void*)"x =", 5, 77, 25, 8},
		{109, 110, 0, 0x0L, EDVAL1, &fcx, 30, 77, 30, 10},
		{110, 111, 0, 0x0L, RTEXT, (void*)"y =", 60, 77, 25, 8},
		{111, 112, 0, 0x0L, EDVAL1, &fcy, 85, 77, 30, 10},
		{112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 117, 77, 15, 8}, 
		{113, 114, 0, 0x0L, EDVAL1, &frad, 62, 89, 30, 10},
		{114, 115, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 94, 89, 15, 8},
		{115, 0, 0, 0x0L, RTEXT, (void*)"radius:", 10, 89, 50, 8},
		{200, 201, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 10, 25, 20, 20},
		{201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 30, 25, 20, 20},
		{202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 50, 25, 20, 20},
		{203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 70, 25, 20, 20},
		{204, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 90, 25, 20, 20},
		{210, 211, 0, 0x0L, LTEXT, (void*)"range for x-data (circular or angular data)", 10, 55, 50, 8},
		{211, 212, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 67, 100, 10},
		{212, 213, 0, 0x0L, LTEXT, (void*)"range for y-data (radial data)", 10, 80, 50, 8},
		{213, 0, 0, LASTOBJ, RANGEINPUT, (void*)text2, 20, 92, 100, 10}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, i, j, k, l, n, ic, cType = 200;
	double x, y;
	bool bRet = false, bType = false;
	AccRange *rX = 0L, *rY = 0L;
	Symbol **Symbols = 0L;
	DataLine *TheLine = 0L;
	TextDEF tlbdef;
	AxisDEF ang_axis, rad_axis;

	if(!parent || !data) return false;
	if(Plots) return Config();
	frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
	fcx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT)*1.5 + frad;
	fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
	UseRangeMark(data, 1, text1, text2);
	tlbdef.ColTxt = defs.Color(COL_AXIS);
	tlbdef.ColBg = 0x00ffffffL;
	tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
	tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
	tlbdef.Style = TXS_NORMAL;
	tlbdef.Mode = TXM_TRANSPARENT;
	tlbdef.Font = FONT_HELVETICA;
	tlbdef.text = 0L;
	if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
	hDlg = CreateDlgWnd("Create Polar Plot", 50, 50, 388, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			break;
		case 5:		case 4:
			bType = true;
			res = -1;
			break;
		case 1:
			if(!bType) {		//the 'Coordinates' sheet must have been visited
				bType = true;
				Dlg->SetCheck(4, 0L, true);
				res = -1;
				}
			break;
		case 200: case 201:	case 202:	case 203:	case 204:
			if(res == 204) {
				Dlg->Activate(211, false);			Dlg->Activate(213, false);
				}
			else if(cType == 204) {
				Dlg->Activate(211, true);			Dlg->Activate(213, true);
				}
			if(res == cType) res = 1;
			else {
				cType = res;
				res = -1;
				}
			break;
			}
		}while (res <0);
	if(res == 1) {
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		//set axis information in ang_axis and rad_axis
		ang_axis.owner = rad_axis.owner = 0L;
		ang_axis.breaks = rad_axis.breaks = 0L;
		ang_axis.nBreaks = rad_axis.nBreaks = 0;
		ang_axis.flags = AXIS_ANGULAR;	
		rad_axis.flags = AXIS_RADIAL | AXIS_DEFRECT;
		Dlg->GetValue(109, &ang_axis.Center.fx);	
		rad_axis.Center.fx = ang_axis.Center.fx;
		Dlg->GetValue(111, &ang_axis.Center.fy);	
		rad_axis.Center.fy = ang_axis.Center.fy;
		Dlg->GetValue(113, &ang_axis.Radius);
		rad_axis.Radius = ang_axis.Radius;
		Dlg->GetValue(102, &ang_axis.min);
		Dlg->GetValue(104, &ang_axis.max);
		Dlg->GetValue(106, &offs);
		ang_axis.loc[0].fy = ang_axis.loc[1].fy = ang_axis.Center.fy + ang_axis.Radius;
		ang_axis.loc[0].fx = ang_axis.Center.fx - ang_axis.Radius;
		ang_axis.loc[1].fx = ang_axis.Center.fx + ang_axis.Radius;
		rad_axis.loc[0].fx = rad_axis.loc[1].fx = 
			parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT);
		rad_axis.loc[0].fy = rad_axis.Center.fy - rad_axis.Radius;
		rad_axis.loc[1].fy = rad_axis.Center.fy;
		if(Dlg->GetText(211, text1, 100) && Dlg->GetText(213, text2, 100) && 
			(rX = new AccRange(text1)) && (rY = new AccRange(text2)) &&
			(n = rX ? rX->CountItems() : 0) && (Plots = (Plot**)calloc(2, sizeof(Plot*)))) {
			if(Dlg->GetCheck(200) || Dlg->GetCheck(201)) 
				Symbols = (Symbol**) calloc(n+1, sizeof(Symbol*));
			if(Dlg->GetCheck(201) || Dlg->GetCheck(202)) 
				TheLine = new DataLine(this, data, text1, text2);
			else if(Dlg->GetCheck(203))
				TheLine = new DataPolygon(this, data, text1, text2);
			else if(Dlg->GetCheck(204)) {
				if(Plots[nPlots++] = new Function(this, data, "Function")){
					if(bRet = Plots[nPlots-1]->PropertyDlg())
						memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
					else {
						DeleteGO(Plots[nPlots-1]);
						Plots[nPlots-1] = 0L;
						}
					}
				}
			rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
			rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
			ic = 0;
			if(Symbols || TheLine) do {
				if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
					CheckBounds(y, y);
					if(Symbols) Symbols[ic++] = new Symbol(this, data, x, y, 
						SYM_CIRCLE, i, j, k, l);
					}
				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
			rad_axis.min = Bounds.Ymin;			rad_axis.max = Bounds.Ymax;
			NiceAxis(&rad_axis, 4);
			ang_axis.Start = ang_axis.Step = 0.0;
			if(Symbols || TheLine) 
				Plots[nPlots++] = new PlotScatt(this, data, ic, Symbols, TheLine);
			if(Plots[0] && (Axes = (GraphObj**)calloc(3, sizeof(Axis*)))){
				Axes[0] = new Axis(this, data, &ang_axis, ang_axis.flags);
				Axes[1] = new Axis(this, data, &rad_axis, 
					rad_axis.flags | AXIS_AUTOTICK | AXIS_NEGTICKS);
				Axes[1]->SetSize(SIZE_LB_XDIST, 
					NiceValue(-DefSize(SIZE_AXIS_TICKS)*6.0)); 
				Axes[1]->SetSize(SIZE_TLB_XDIST, 
					NiceValue(-DefSize(SIZE_AXIS_TICKS)*2.0)); 
				Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
				nAxes = 2;
				bRet = true;
				}
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;	if(rY) delete rY;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Box plot properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int boxplot_mode_sel = 52;
bool
BoxPlot::PropertyDlg()
{
	DlgInfo PlotDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
		{2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
		{10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{50, 60, 51, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{51, 52, 0, 0x0L, LTEXT, (void*)"Data Source:", 10, 12, 40, 9},
		{52, 53, 0, TOUCHEXIT, RADIO2, (void*)" user values", 60, 12, 50, 9},
		{53, 0, 0, TOUCHEXIT, RADIO2, (void*)" statistical data", 60, 22, 60, 9},
		{60, 61, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{61, 0, 200, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{100, 102, 0, 0x0L, LTEXT, (void*)"range for grouping variable (X data)", 10, 39, 140, 9},
		{102, 103, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
		{103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 60, 90, 9},
		{104, 150, 0, 0x0L, RANGEINPUT, TmpTxt+200, 10, 70, 165, 10},
		{150, 160, 151, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 87, 165, 45},
		{151, 152, 0, 0x0L, CHECKBOX, (void*)" line", 15, 92, 50, 9},
		{152, 153, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 101, 50, 9},
		{153, 154, 0, 0x0L, LTEXT, (void*)"using", 65, 101, 30, 9},
		{154, 155, 0, 0x0L, RADIO1, (void*)" arithmetic mean", 95, 90, 50, 9},
		{155, 156, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 99, 50, 9},
		{156, 157, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 108, 50, 9},
		{157, 0, 0, CHECKED, RADIO1, (void*)" median", 95, 117, 50, 9},
		{160, 170, 161, ISPARENT | CHECKED, GROUPBOX, (void*) " draw boxes ", 10, 137, 165, 38},
		{161, 162, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 142, 70, 9},
		{162, 163, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 151, 70, 9},
		{163, 164, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" 25, 75% percentiles", 95, 142, 70, 9},
		{164, 165, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 151, 70, 9},
		{165, 166, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 161, 70, 9},
		{166, 167, 0, 0x0L, EDVAL1, &ci_box, 28, 160, 15, 10},
		{167, 0, 0, 0x0L, LTEXT, (void*) "%  conf. interval", 45, 161, 70, 9},
		{170, 400, 171, ISPARENT | CHECKED, GROUPBOX, (void*) " draw whiskers ", 10, 180, 165, 38},
		{171, 172, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 185, 70, 9},
		{172, 173, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 194, 70, 9},
		{173, 174, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 185, 70, 9},
		{174, 175, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" min and max", 95, 194, 70, 9},
		{175, 176, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 204, 70, 9},
		{176, 177, 0, 0x0L, EDVAL1, &ci_err, 28, 203, 15, 10},
		{177, 0, 0, 0x0L, LTEXT, (void*) "%  conf. interval", 45, 203, 70, 9},
		{200, 202, 0, 0x0L, LTEXT, (void*)"range for common X values", 10, 39, 140, 9},
		{202, 250, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
		{250, 260, 251, ISPARENT | CHECKED, GROUPBOX, (void*) "                        ", 10, 68, 165, 30},
		{251, 252, 0, 0x0L, CHECKBOX, (void*)" draw line", 15, 63, 50, 9},
		{252, 253, 0, 0x0L, LTEXT, (void*)"range for line values", 15, 73, 80, 9},
		{253, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 83, 155, 10},
		{260, 270, 261, ISPARENT | CHECKED, GROUPBOX, (void*) "                               ", 10, 106, 165, 30},
		{261, 262, 0, CHECKED, CHECKBOX, (void*)" draw symbols", 15, 101, 50, 9},
		{262, 263, 0, 0x0L, LTEXT, (void*)"range for symbol values", 15, 111, 80, 9},
		{263, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 121, 155, 10},
		{270, 280, 271, ISPARENT | CHECKED, GROUPBOX, (void*) "                          ", 10, 144, 165, 50},
		{271, 272, 0, CHECKED, CHECKBOX, (void*)" draw boxes", 15, 139, 50, 9},
		{272, 273, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 149, 80, 9},
		{273, 274, 0, 0x0L, RANGEINPUT, TmpTxt+300, 15, 159, 155, 10},
		{274, 275, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 169, 80, 9},
		{275, 0, 0, 0x0L, RANGEINPUT, TmpTxt+400, 15, 179, 155, 10},
		{280, 0, 281, ISPARENT | CHECKED, GROUPBOX, (void*) "                              ", 10, 202, 165, 50},
		{281, 282, 0, CHECKED, CHECKBOX, (void*)" draw whiskers", 15, 197, 50, 9},
		{282, 283, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 207, 80, 9},
		{283, 284, 0, 0x0L, RANGEINPUT, TmpTxt+500, 15, 217, 155, 10},
		{284, 285, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 227, 80, 9},
		{285, 0, 0, 0x0L, RANGEINPUT, TmpTxt+600, 15, 237, 155, 10},
		{400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 223, 165, 30},
		{401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 228, 70, 9},
		{402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 228, 70, 9},
		{403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 238, 24, 9},
		{404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 237, 30, 10}};
	DlgRoot *Dlg;
	void *hDlg;
	bool bRet = false;
	int i, j, k, k1, l, l1, n, ic, c, res, cb, width, height;
	double x, y1, y2, dx, dy;
	char errdesc[40], boxdesc[40], symdesc[40];
	lfPOINT fp1, fp2;
	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
	AccRange *rX = 0L, *rY1 = 0L, *rY2 = 0L;

	if(!parent || !data) return false;
	UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400, TmpTxt+500, TmpTxt+600);
	ci_box = ci_err = 95.0;
	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
	TmpTxt[0] = TmpTxt[100] = 0;
	//restore previous style
	if(boxplot_mode_sel == 53) {
		Dlg->ShowItem(61, false);			Dlg->SetCheck(53, 0L, true);
		}
	else {
		Dlg->SetCheck(52, 0L, true);		Dlg->ShowItem(60, false);
		}
	hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 370, 550, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(Dlg->GetCheck(10)) res=-1;
			break;
		case 52:	case 53:
			boxplot_mode_sel = res;
			if(res == 53) {
				Dlg->ShowItem(60, true);	Dlg->ShowItem(61, false);
				}
			else {
				Dlg->ShowItem(60, false);	Dlg->ShowItem(61, true);
				}
			Dlg->Command(CMD_REDRAW, 0L, 0L);	res=-1;
			break;
			}
		}while (res <0);
	if(res == 1) {
		type = 0;				dirty = true;
		if(Dlg->GetCheck(52) && Dlg->GetText(202, TmpTxt+100, 50) && TmpTxt[100] &&(rX = new AccRange(TmpTxt+100))) {
			xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
			n = rX->CountItems();	nPoints = n;
			//  data line
			if(n > 1 && Dlg->GetCheck(251) && Dlg->GetText(253, TmpTxt, TMP_TXT_SIZE)) {
				TheLine = new DataLine(this, data, TmpTxt+100, TmpTxt);
				bRet = true;
				}
			// symbols
			if(n > 0 && Dlg->GetCheck(261) && Dlg->GetText(263, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] 
				&& (Symbols = (Symbol**)calloc(n, sizeof(Symbol*)))
				&& (rY1 = new AccRange(TmpTxt))) {
				yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);
				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);
				ic = c = 0;
				do {
					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1)) {
						if(Symbols[ic] = new Symbol(this, data, x, y1, SYM_PLUS, i, j, k, l))
							Symbols[ic++]->idx = c;
						}
					c++;
					}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
				delete rY1;		rY1 = 0L;
				if(ic) bRet = true;
				}
			// boxes
			if(n > 0 && Dlg->GetCheck(271) && Dlg->GetText(273, TmpTxt+300, 50) && Dlg->GetText(275, TmpTxt+400, 50)
				&& (Boxes = (Box**)calloc(n, sizeof(Box*)))
				&& (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);	rY2->GetFirst(&k1, &l1);
				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);	rY2->GetNext(&k1, &l1);
				ic = 0;
				do {
					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
						fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
						Boxes[ic] = new Box(this, data, fp1, fp2, BAR_RELWIDTH, i, j, k, l, i, j, k1, l1);
						if(Boxes[ic]) Boxes[ic++]->SetSize(SIZE_BOX, 60.0);
						}
					}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
				delete rY1;		rY1 = 0L;		delete rY2;		rY2 = 0L;
				if(ic) bRet = true;
				}
			// whiskers
			if(n > 0 && Dlg->GetCheck(281) && Dlg->GetText(283, TmpTxt+300, 50) && Dlg->GetText(285, TmpTxt+400, 50)
				&& (Whiskers = (Whisker**)calloc(n, sizeof(Whisker*)))
				&& (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
				rX->GetFirst(&i, &j);	rY1->GetFirst(&k, &l);	rY2->GetFirst(&k1, &l1);
				rX->GetNext(&i, &j);	rY1->GetNext(&k, &l);	rY2->GetNext(&k1, &l1);
				ic = 0;
				do {
					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
						fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
						Whiskers[ic++] = new Whisker(this, data, fp1, fp2, 0, i, j, k, l, i, j, k1, l1);
						}
					}while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
				delete rY1;		rY1 = 0L;		delete rY2;		rY2 = 0L;
				if(ic) bRet = true;
				}
			if (bRet) Command(CMD_AUTOSCALE, 0L, 0L);
			}
		else if(Dlg->GetText(102, TmpTxt+100, 50) && TmpTxt[100] && Dlg->GetText(104, TmpTxt+200, 50) && TmpTxt[200]){
			xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
			yRange = (char*)memdup(TmpTxt+200, ((int)strlen(TmpTxt+200))+2, 0);
			if((rX = new AccRange(xRange)) && (rY1 = new AccRange(yRange))) {
				x_info = rX->RangeDesc(data, 2);		y_info = rY1->RangeDesc(data, 2);
				delete rX;		delete rY1;		rX = rY1 = 0L;
				}
			if(Dlg->GetCheck(154)) type |= 0x0001;		if(Dlg->GetCheck(155)) type |= 0x0002;
			if(Dlg->GetCheck(156)) type |= 0x0003;		if(Dlg->GetCheck(157)) type |= 0x0004;
			if(Dlg->GetCheck(161)) type |= 0x0010;		if(Dlg->GetCheck(162)) type |= 0x0020;
			if(Dlg->GetCheck(163)) type |= 0x0030;		if(Dlg->GetCheck(164)) type |= 0x0040;
			if(Dlg->GetCheck(165)) type |= 0x0050;
			if(Dlg->GetCheck(171)) type |= 0x0100;		if(Dlg->GetCheck(172)) type |= 0x0200;
			if(Dlg->GetCheck(173)) type |= 0x0300;		if(Dlg->GetCheck(174)) type |= 0x0400;
			if(Dlg->GetCheck(175)) type |= 0x0500;
			if(Dlg->GetCheck(151)) type |= 0x1000;		if(Dlg->GetCheck(152)) type |= 0x2000;
			if(Dlg->GetCheck(401)) type |= 0x4000;		if(Dlg->GetCheck(402)) type |= 0x8000;
			Dlg->GetValue(166, &ci_box);				Dlg->GetValue(176, &ci_err);
			if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
			CreateData();
			if(curr_data && type) {
				curr_data->GetSize(&width, &height);
#ifdef USE_WIN_SECURE
				sprintf_s(TmpTxt+100, 50, "a1:a%d", height);	sprintf_s(TmpTxt+200, 50, "b1:b%d", height);
#else	
				sprintf(TmpTxt+100, "a1:a%d", height);			sprintf(TmpTxt+200, "b1:b%d", height);
#endif
				nPoints = height;
				if(nPoints > 1 && (type & 0x1000)) {
					TheLine = new DataLine(this, curr_data, TmpTxt+100, TmpTxt+200);
					bRet = true;
					}
				if(nPoints > 0 && (type & 0x2000) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
					switch(type & 0x000f) {
					case 0x0001:	cb = rlp_strcpy(symdesc, 40, "Mean");				break;
					case 0x0002:	cb = rlp_strcpy(symdesc, 40, "Geometric mean");		break;
					case 0x0003:	cb = rlp_strcpy(symdesc, 40, "Harmonic mean");		break;
					case 0x0004:	cb = rlp_strcpy(symdesc, 40, "Median");				break;
					default:		cb = rlp_strcpy(symdesc, 40, "n.a.");				break;
						}
					for(i = 0; i < height; i++) {
						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y1)
							&& (Symbols[i] = new Symbol(this, curr_data, x, y1, SYM_PLUS, 0, i, 1, i))){
							Symbols[i]->idx = i;
							Symbols[i]->name = (char*)memdup(symdesc, cb+1, 0);
							}
						}
					bRet = true;
					}
				if(nPoints > 0 && (type & 0x00f0) && (Boxes = (Box**)calloc(nPoints, sizeof(Box*)))) {
					switch(type & 0x00f0) {
					case 0x0010:	cb = rlp_strcpy(boxdesc, 40, "Std. Dev.");			break;
					case 0x0020:	cb = rlp_strcpy(boxdesc, 40, "Std. Err.");			break;
					case 0x0030:	cb = rlp_strcpy(boxdesc, 40, "25, 75% Perc.");		break;
					case 0x0040:	cb = rlp_strcpy(boxdesc, 40, "Min./Max.");			break;
#ifdef USE_WIN_SECURE
					case 0x0500:	cb = sprintf_s(boxdesc, 40, "'%g%% CI", ci_err);	break;
#else
					case 0x0500:	cb = sprintf(boxdesc, "'%g%% CI", ci_err);			break;
#endif
					default:		cb = rlp_strcpy(boxdesc, 40, "n.a.");
						}
					for(i = 0; i < height; i++) {
						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 2, &y1)
							&&	curr_data->GetValue(i, 3, &y2)) {
							fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
							Boxes[i] = new Box(this, curr_data, fp1, fp2, BAR_RELWIDTH, 0, i, 2, i, 0, i, 3, i);
							if(Boxes[i]){
								Boxes[i]->SetSize(SIZE_BOX, 60.0);
								Boxes[i]->name = (char*)memdup(boxdesc, cb+1, 0);
								}
							}
						}
					bRet = true;
					}
				if(nPoints > 0 && (type & 0x0f00) && (Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*)))) {
					switch(type & 0x0f00) {
					case 0x0100:	rlp_strcpy(errdesc, 40, "Std. Dev.");			break;
					case 0x0200:	rlp_strcpy(errdesc, 40, "Std. Err.");			break;
					case 0x0300:	rlp_strcpy(errdesc, 40, "25, 75% Perc.");		break;
					case 0x0400:	rlp_strcpy(errdesc, 40, "Min./Max.");			break;
#ifdef USE_WIN_SECURE
					case 0x0500:	sprintf_s(errdesc, 40, "'%g%% CI", ci_err);		break;
#else
					case 0x0500:	sprintf(errdesc, "'%g%% CI", ci_err);			break;
#endif
					default:		rlp_strcpy(errdesc, 40, "error");
						}
					for(i = 0; i < height; i++) {
						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 4, &y1)
							&&	curr_data->GetValue(i, 5, &y2)) {
							fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
							Whiskers[i] = new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 4, i, 0, i, 5, i);
							if(Whiskers[i]) Whiskers[i]->Command(CMD_ERRDESC, errdesc, 0L);
							}
						}
					bRet = true;
					}
				if(nPoints > 0 && (type & 0xc000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
					dy = -0.4 * DefSize(SIZE_SYMBOL);
					if(type & 0x4000){
						lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
						dx = 0.0;
						}
					else {
						lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
						dx = -dy;
						}
					for(i = 0; i < height; i++) {
						if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 7, TmpTxt, TMP_TXT_SIZE)){
							if(curr_data->GetValue(i, 6, &y1))Labels[i] = new Label(this, curr_data, x, y1, &lbdef, 
								LB_X_DATA | LB_Y_DATA, 0, i, 6, i, 7, i);
							if(Labels[i]){
								Labels[i]->SetSize(SIZE_LB_YDIST, dy);	Labels[i]->SetSize(SIZE_LB_XDIST, dx);
								}
							}
						}
					bRet = true;
					}
				}
			}
		}
	if(bRet) {
		dirty = true;
		Command(CMD_AUTOSCALE, 0L, 0L);
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create density distribution plot 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
DensDisp::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 52, 10, "Style"};
	char text1[100], text2[100];
	DlgInfo PlotDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 148, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 148, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 100},
		{5, 10, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 130, 100},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"range for direction (time, depth) data", 10, 30, 60, 8},
		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
		{102, 103, 0, 0x0L, LTEXT, (void*)"range for width (density) data", 10, 55, 60, 8},
		{103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 65, 100, 10},
		{104, 0, 0, 0x0L, CHECKBOX, (void*)"vertical profile", 10, 90, 100, 8},
		{200, 201, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 30, 90, 45},
		{201, 202, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)"symmetric bars", 25, 80, 60, 8},
		{202, 203, 0, TOUCHEXIT, RADIO1, 0L, 25, 88, 60, 8},
		{203, 0, 0, TOUCHEXIT | LASTOBJ, RADIO1, 0L, 25, 96, 60, 9}};
	DlgRoot *Dlg;
	void *hDlg;
	int n, res, align = 0;
	bool bRet = false, bContinue = false, bVert;
	AccRange *rX = 0L, *rY = 0L;

	if(!parent || !data) return false;
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
	UseRangeMark(data, 1, text1, text2);
	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
	hDlg = CreateDlgWnd("Density profile", 50, 50, 420, 260, Dlg, 0x4L);
	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 5:
			if(Dlg->GetCheck(104)) {
				Dlg->SetText(202, "bars right");	Dlg->SetText(203, "bars left");
				}
			else {
				Dlg->SetText(202, "bars up");		Dlg->SetText(203, "bars down");
				}
			res = -1;
			break;
		case 201:	case 202:	case 203:
			align = res - 201;
			res = -1;
			break;
		case 1:
			if(rX) delete rX;	if(rY) delete rY;
			rX = rY = 0L;
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
			n = rX ? rX->CountItems() : 0;
			if(!n) {
				ErrorBox("direction range not specified\nor not valid.");
				bContinue = true;
				res = -1;
				}
			if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
				if(n != rY->CountItems()) {
					ErrorBox("both ranges must be given\nand must have the same size");
					bContinue = true;
					res = -1;
					}
				}
			}
		}while (res < 0);
	if(res == 1 && n && rX && rY) {
		if(Dlg->GetCheck(104)) {
			y_info = rX->RangeDesc(data, 0);		x_info = rY->RangeDesc(data, 0);
			}
		else {
			x_info = rX->RangeDesc(data, 0);		y_info = rY->RangeDesc(data, 0);
			}
		type = (bVert = Dlg->GetCheck(104)) ? align | 0x10 : align;
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&DefLine, 0);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&DefFill, 0);
		if(DefFill.hatch) memcpy(&DefFillLine, DefFill.hatch, sizeof(LineDEF));
		DefFill.hatch = &DefFillLine;
		DoUpdate();
		bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;		if(rY) delete rY;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create stacked bar or stacked polygon 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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"};
	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, currYR = 0, maxYR = 0, nx = 0, ny, c_num, c_txt, c_datetime;
	bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
	char **rd = 0L, *rname;
	AccRange *rX = 0L, *rY = 0L;
	TextValue *tv = 0L;

	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(!(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++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);	 maxYR = j-1;
		}
	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
	hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked Bar Plot" : 
		(char*)"Stacked Polygons", 50, 50, 420, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(156, true);				Dlg->Activate(101, false);
				}
			else {
				Dlg->ShowItem(156, false);				Dlg->Activate(101, true);
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			Dlg->SetText(153, TmpTxt);
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		ny = 0;
		if(rX) delete rX;		rX = 0L;
		switch(res) {
		case 0:
			if(bContinue || Dlg->GetCheck(20)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 1:		
			Dlg->GetValue(203, &StartVal);
			bSub = Dlg->GetCheck(201);			bHor = Dlg->GetCheck(204);
		case 155:		case 156:
			res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			break;
			}
		}while (res < 0);
	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]){	//accept settings and create plot
		maxYR++;
		for(i = j = 0; i < maxYR; i++) {
			if(i) TmpTxt[j++] = '&';
			j+= rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, rd[i]);
			}
		rX->DataTypes(data, &c_num, &c_txt, &c_datetime);
		if(!c_num && (c_txt + c_datetime) > 0 ) tv = new TextValue();
		if(Dlg->GetCheck(204)) {
			y_info = rX->RangeDesc(data, 3);	y_tv = tv;
			}
		else {
			x_info = rX->RangeDesc(data, 3);	x_tv = tv;
			}
		ssYrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssXrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);;
		cum_data_mode = Dlg->GetCheck(200) ? 1 : 2;
		if(Id == GO_STACKPG) cum_data_mode += 2;
		CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		//do stacked bar
		if(rY)delete rY;	rY = 0L;
		if(Id == GO_STACKBAR){
			numPlots = maxYR;
			if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*))) 
				for(i = sc = 0; i < (maxYR) && rd[i] && *rd[i]; i++) {
					rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 3);
					if(Boxes[i]= new BoxPlot(0L, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);	Boxes[i]->parent = this;
					Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
					Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
					Boxes[i]->SetSize(SIZE_BOX, 60.0);
					if(rname) free(rname);	delete rY;	rY = 0L;
					}
				}
			}
		//do stacked polygon
		else if(Id == GO_STACKPG){
			numPG = maxYR;
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, 20, "a1:a%d", nx*2);
#else
			sprintf(TmpTxt, "a1:a%d", nx*2);
#endif
			if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))
				for(i=sc=0; i < maxYR && rd[i] && *rd[i];i++){
#ifdef USE_WIN_SECURE
				sprintf_s(TmpTxt+20, 20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
#else
				sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
#endif
				rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 3);
				if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt, rname);
				else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20, rname);
				if(Polygons[i]) {
					Polygons[i]->Command(CMD_AUTOSCALE, 0L, 0L);
					Polygons[i]->Command(CMD_PG_FILL, GetSchemeFill(&sc), 0L);
					}
				if(rname) free(rname);	delete rY;	rY = 0L;
				}
			}
		if(Bounds.Xmax >= Bounds.Xmin && Bounds.Ymax >= Bounds.Ymin) bRet = true;
		else bRet = false;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rd) {
		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
		free(rd);
		}
	if(rX) delete rX;		if(rY) delete rY;		free(StackBarDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create grouped bars chart
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *GBDlg_Tmpl =
	"1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
	".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
	".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,+,99,ISPARENT | CHECKED | TOUCHEXIT,SHEET,1,5,10,128,100\n"
	".,.,200,ISPARENT,SHEET,2,5,10,128,100\n"
	".,.,300,ISPARENT,SHEET,3,5,10,128,100\n"
	".,10,250,ISPARENT | TOUCHEXIT,SHEET,16,5,10,128,100\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"99,100,110,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"100,,160,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"101,+,,,LTEXT,0,25,39,60,8\n"
	".,.,,,RANGEINPUT,-15,25,49,100,10\n"
	".,.,,,LTEXT,0,25,61,60,8\n"
	".,.,,,RANGEINPUT,-16,25,71,100,10\n"
	".,.,,,PUSHBUTTON,-8,95,87,30,12\n"
	".,,,,PUSHBUTTON,-9,60,87,35,12\n"
	"110,+,,,LTEXT,4,10,25,60,8\n"
	".,150,,,LTEXT,5,10,33,60,8\n"
	"150,,153,ISPARENT | CHECKED,GROUPBOX,6,10,50,118,55\n"
	"160,101,,ISPARENT | CHECKED,GROUPBOX,19,10,30,118,75\n"
	"153,+,,,LTEXT,0,15,60,60,8\n"
	".,.,,,RANGEINPUT,-1,15,70,108,10\n"
	".,.,,,PUSHBUTTON,-8,93,87,30,12\n"
	".,,,,PUSHBUTTON,-9,58,87,35,12\n"
	"200,+,,,RTEXT,7,10,35,38,8\n"
	".,.,,,EDVAL1,8,58,35,35,10\n"
	".,.,,,RTEXT,9,10,50,38,8\n"
	".,.,,,EDVAL1,10,58,50,35,10\n"
	".,.,,,RTEXT,11,10,65,38,8\n"
	".,.,,,EDVAL1,12,58,65,35,10\n"
	".,.,,,LTEXT,-10,95,65,8,8\n"
	".,.,,,RTEXT,13,10,80,38,8\n"
	".,.,,,EDVAL1,14,58,80,35,10\n"
	".,,,,LTEXT,-10,95,80,8,8\n"
	"250,+,TOUCHEXIT,CHECKED,RADIO1,17,20,35,70,8\n"
	".,.,,TOUCHEXIT,RADIO1,18,20,50,70,8\n"
	".,,,,RANGEINPUT,0,15,65,108,10\n"
	"300,,,LASTOBJ | NOSELECT,ODBUTTON,15,24,30,90,60";

bool
GroupBars::PropertyDlg()
{
	TabSHEET tab1 = {0, 27, 10, "Data"};
	TabSHEET tab2 = {27, 59, 10, "Details"};
	TabSHEET tab3 = {59, 96, 10, "Scheme"};
	TabSHEET tab4 = {96, 128, 10, "Labels"};
	double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"Get values from spreadsheet:",
		(void*)"All ranges should have equal size!", (void*)" ranges for y values ", (void*)"start value",
		(void*)&start, (void*)"group step", (void*)&step, (void*)"bar width", (void*)&bw,
		(void*)"group gap", (void*)&gg, (void*)(OD_scheme), (void*)&tab4, (void*)" no group labels",
		(void*)"from spreadsheet range:", (void*)" ranges for y- and error- data "};
	DlgInfo *GBDlg;
	DlgRoot *Dlg;
	void *hDlg;
	bool bRet = false, updateYR = true, bContinue = false, bError;
	char **rd=0L, **rdx=0L, **rdy=0L, *desc;
	Bar **bars = 0L;
	ErrorBar **errs = 0L;
	AccRange *rX = 0L, *rY = 0L;
	anyResult ares;
	int i, j, ic, res, ix, iy, ex, ey, ny, s1, s2, sc = 0, currYR = 0, maxYR = 0;
	double x, y, xinc, e, ebw;
	
	if(!parent || !data) return false;
	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
	if(!(GBDlg = CompileDialog(GBDlg_Tmpl, dyndata)))return false;
	if(mode == 0 && TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
		for(i=0, j= 0; i <= 1000; i +=100) 
			if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
			maxYR = j-1;
		}
	else if(mode == 1 && TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*))) 
		&& (rdy = (char**)calloc(12, sizeof(char*)))) {
		for(i=j=0; i <= 1000; i +=200) if(TmpTxt[i]) {
			rdx[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt)+1, 0);	
			rdy[j] = (char*)memdup(TmpTxt+i+100, (int)strlen(TmpTxt+i+100)+1, 0);		maxYR = j++;
			}
		}
	Id = GO_STACKBAR;
	if(mode == 0 && !rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
	if(mode == 1 && !rdx && !rdy && !(rdx = (char**)calloc(1, sizeof(char*))) 
		&& !(rdy = (char**)calloc(1, sizeof(char*))))return false;
	if(!(Dlg = new DlgRoot(GBDlg, data)))return false;
	if(mode == 1) {
		Dlg->ShowItem(99, false);		Dlg->ShowItem(100, true);
		}
	else {
		Dlg->ShowItem(99, true);		Dlg->ShowItem(100, false);
		}
	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
	else Dlg->SetText(154, "");
	hDlg = CreateDlgWnd(mode == 0 ? (char*)"Grouped Bar Chart" : (char*)"Grouped Bar Chart with Error Bars", 50, 50, 390, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(156, true);		Dlg->ShowItem(106, true);
				}
			else {
				Dlg->ShowItem(156, false);		Dlg->ShowItem(106, false);		
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
			sprintf_s(TmpTxt+100, 20, "errors # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
			sprintf(TmpTxt+100,"errors # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			if(mode == 0) 	Dlg->SetText(153, TmpTxt);
			else {
				Dlg->SetText(101, TmpTxt);		Dlg->SetText(103, TmpTxt+100);
				}
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(bContinue || Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 250:		case 251:
		case 7:
			Dlg->Activate(252, true);
			res = -1;			break;
		case 4:
			Dlg->Activate(mode ? 102:154, true);
			res = -1;			break;
		case 1:		
			Dlg->GetValue(201, &start);			Dlg->GetValue(203, &step);
			Dlg->GetValue(205, &bw);			Dlg->GetValue(208, &gg);
			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			if(!mode) break;
		case 105:										//next button
			bError=false;	s1 = s2 = 0;
			if(Dlg->GetText(102, TmpTxt, 100)) {
				if(rX = new AccRange(TmpTxt)) {
					s1 = rX->CountItems();
					if(s1 < 2) {
						ErrorBox("y-range not valid");
						bContinue=bError=true;
						Dlg->Activate(102, true);
						}
					delete rX;
					}
				else bError = true;
				}
			else bError = true;
			if(Dlg->GetText(104, TmpTxt+100, 100) && !bError) {
				if(rY = new AccRange(TmpTxt+100)) {
					s2 = rY->CountItems();
					if(s2 < 2) {
						ErrorBox("error-range not valid");
						bContinue=bError=true;
						Dlg->Activate(104, true);
						}
					delete rY;
					}
				else bError = true;
				}
			else {
				Dlg->Activate(104, true);
				bError = true;
				}
			if(!s1 || !s2) bError = true;
			rX = rY = 0L;
			if(!bError && s1!=s2) {
				ErrorBox("Y-range and error-range are\ndifferent in size");
				bContinue=bError=true;
				}
			if(!bError) {
				if((currYR+1) > maxYR) {
					rdx = (char**)realloc(rdx, sizeof(char*)*(currYR+2));
					rdy = (char**)realloc(rdy, sizeof(char*)*(currYR+2));
					rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
					maxYR = currYR+1;
					}
				if(rdx[currYR]) free(rdx[currYR]);		//store x-range
				rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
				if(rdy[currYR]) free(rdy[currYR]);		//store y range
				rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
				updateYR = true;						currYR++;
				Dlg->SetText(102, rdx[currYR]);			Dlg->SetText(104, rdy[currYR]);
				Dlg->Activate(102, true);				
				if(res != 1) res = -1;
				}
			else if(res != 1){
				bContinue = true;
				res = -1;
				}
			break;
		case 106:										//prev button
			if(Dlg->GetText(102, TmpTxt, 100) && Dlg->GetText(104, TmpTxt+100, 100)){
				if(rdx[currYR]) free(rdx[currYR]);		if(rdy[currYR]) free(rdy[currYR]);
				rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
				rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
				}
			else if(currYR == maxYR) maxYR--;
			currYR--;	
			Dlg->SetText(102, rdx[currYR]);
			Dlg->SetText(104, rdy[currYR]);				Dlg->Activate(102, true);
			updateYR = true;
			res = -1;
			break;
		case 155:		case 156:
			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			break;
			}
		} while(res < 0);
	if(res == 1 && ((rd && rd[0] && rd[0][0])||(rdx && rdy && rdx[0] && rdy[0] && rdx[0][0] && rdy[0][0]))){
		//accept settings and create plots
		if((mode == 0 && rd[maxYR]) || (mode == 1 && rdx[maxYR])) maxYR++;
		ebw = defs.GetSize(SIZE_ERRBAR)*9.0/((double)(s1*maxYR));
		if(Dlg->GetCheck(251) && Dlg->GetText(252, TmpTxt, 100) && (rX = new AccRange(TmpTxt))
			&& rX->GetFirst(&ix, &iy)){
			x_tv = new TextValue();				rX->GetNext(&ix, &iy);
			i = 1;								start = step = 1.0;
			do {
				if(data->GetResult(&ares, iy, ix, false)) switch(ares.type) {
					case ET_TEXT:
						x_tv->GetValue(ares.text);			break;
					case ET_VALUE:		case ET_DATE:		case ET_TIME:
					case ET_DATETIME:	case ET_BOOL:
						TranslateResult(&ares);
						x_tv->GetValue(ares.text);			break;
					}
				i++;
				}while(rX->GetNext(&ix, &iy));
			}
		if(rX) delete rX;							rX = 0L;
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		if(!(xyPlots = (PlotScatt**)calloc(maxYR, sizeof(PlotScatt*)))){
			CloseDlgWnd(hDlg);
			delete Dlg;
			if(rd) {
				for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
				free(rd);
				}
			return false;
			}
		xinc = fabs(step / ((double)maxYR + gg/100.0));
		start -= (xinc * ((double)maxYR-1))/2.0;
		for(i = 0, desc = 0L; i < maxYR; i++) {
			x = start + xinc * (double)i;
			if(mode == 0 && rd) {
				if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
				else {
					rY = 0L;	ny = 0;
					}
				}
			else if(mode == 1 && rdx && rdy) {
				if(rdx[i] && (rY = new AccRange(rdx[i]))) ny = rY->CountItems();
				else {
					rY = 0L;	ny = 0;
					}
				}
			if(rY) {
				desc = rY->RangeDesc(data, 1);
				rY->GetFirst(&ix, &iy);
				if(mode == 1 && (rX = new AccRange(rdy[i]))) {
					errs = (ErrorBar**)calloc(ny, sizeof(ErrorBar*)); 
					rX->GetFirst(&ex, &ey);
					}
				rY->GetNext(&ix, &iy);
				if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
					for(ic = 0; ic < ny; ic++) {
						if(bContinue = data->GetValue(iy, ix, &y)){
							bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
								-1, -1, ix, iy, desc);
							CheckBounds(x, y);
							}
						if(errs && rX && rX->GetNext(&ex, &ey) && data->GetValue(ey, ex, &e)) {
							if(bContinue && (errs[ic] = new ErrorBar(0L, data, x, y, e, 0, -1, -1, ix, iy, ex, ey)))
								errs[ic]->SetSize(SIZE_ERRBAR, ebw);
							CheckBounds(x, y+e);	CheckBounds(x, y-e);
							}
						x += step;
						rY->GetNext(&ix, &iy);
						}
					xyPlots[numXY++] = new PlotScatt(this, data, ic, bars, errs);
					if(xyPlots[i]) {
						xyPlots[i]->SetSize(SIZE_BARMINX, xinc);
						xyPlots[i]->SetSize(SIZE_BAR, bw);
						xyPlots[i]->Command(CMD_BAR_FILL, GetSchemeFill(&sc), 0L);
						}
					for(ic = 0; ic < ny; ic++) if(bars[ic]) delete(bars[ic]);
					if(errs) for(ic = 0; ic < ny; ic++) if(errs[ic]) delete(errs[ic]);
					free(bars);		if(errs) free(errs);	bRet = true;
					}
				delete(rY);		if(desc) free(desc);		rY = 0L;
				}
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rd) {
		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
		free(rd);
		}
	if(rdx) {
		for (i = 0; i < maxYR; i++)	if(rdx[i]) free(rdx[i]);
		free(rdx);
		}
	if(rdy) {
		for (i = 0; i < maxYR; i++)	if(rdy[i]) free(rdy[i]);
		free(rdy);
		}
	if(rY) delete rY;		if(rX) delete rX;		free(GBDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create a waterfall graph
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Waterfall::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Details"};
	TabSHEET tab3 = {55, 90, 10, "Scheme"};
	static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
	static DWORD defcol = 0x0L;
	char text1[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, 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, 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},
		{201, 202, 0, 0x0L, RTEXT, (void*)"dx =", 28, 45, 13, 8},
		{202, 203, 0, 0x0L, EDVAL1, &dspm.fx, 43, 45, 25, 10},
		{203, 204, 0, 0x0L, RTEXT, (void*)"dy =", 73, 45, 13, 8},
		{204, 205, 0, 0x0L, EDVAL1, &dspm.fy, 88, 45, 25, 10},
		{205, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 45, 15, 8}, 
		{300, 301, 0, CHECKED, RADIO1, (void*)" common color for lines:", 20, 35, 80, 9},
		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&defcol, 105, 35, 20, 10},
		{302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[0], 25, 70, 10, 10},
		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[1], 37, 70, 10, 10},
		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[2], 49, 70, 10, 10},
		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[3], 61, 70, 10, 10},
		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[4], 73, 70, 10, 10},
		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[5], 85, 70, 10, 10},
		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[6], 97, 70, 10, 10},
		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[7], 109, 70, 10, 10},
		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
	DlgRoot *Dlg;
	void *hDlg;
	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;
	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++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
			maxYR = j-1;
		}
	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
	hDlg = CreateDlgWnd("Create Waterfall Plot", 50, 50, 420, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(156, true);				Dlg->Activate(101, false);
				}
			else {
				Dlg->ShowItem(156, false);				Dlg->Activate(101, true);
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			Dlg->SetText(153, TmpTxt);
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		ny = 0;
		if(rX) delete rX;
		rX = 0L;
		switch(res) {
		case 0:
			if(bContinue || Dlg->GetCheck(20)) res = -1;
			break;
		case -1:
			bContinue = false;			break;
		case 1:
			for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
			Dlg->GetColor(301, &defcol);
			bUseSch = Dlg->GetCheck(302);
			Dlg->GetValue(202, &dspm.fx);	Dlg->GetValue(204, &dspm.fy);
			//execute com_StackDlg for <OK>
		case 155:		case 156:
			res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			break;
		case 301:
			Dlg->SetCheck(300, 0L, true);
			res = -1;	break;
		case 303:	case 304:	case 305:	case 306:
		case 307:	case 308:	case 309:	case 310:
			Dlg->SetCheck(302, 0L, true);
			res = -1;	break;
			}
		}while (res < 0);
	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
		maxYR++;
		numPL = maxYR;
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		Dlg->GetText(101, text1, 100);
		if(Lines=(DataLine**)calloc(numPL,sizeof(DataLine*)))for(i=0;i<maxYR;i++){
			if(rd[i] && rd[i][0]) Lines[i] = new DataLine(this, data, text1, rd[i]);
			if(Lines[i]) {
				if(bUseSch) Lines[i]->SetColor(COL_DATA_LINE, colarr[(i & 0x07)]);
				else Lines[i]->SetColor(COL_DATA_LINE, defcol);
				bRet = true;
				}
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rd) {
		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
		free(rd);
		}
	if(rX) delete rX;		if(rY) delete rY;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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,12,300,ISPARENT,SHEET,2,5,10,140,100\n"
	"12,20,200,ISPARENT,SHEET,15,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"
	"200,201,,CHECKED,CHECKBOX,16,25,35,80,9\n"
	"201,202,,ODEXIT,SYMBUTT,17,25,70,10,10\n"
	"202,203,,ODEXIT,SYMBUTT,18,37,70,10,10\n"
	"203,204,,ODEXIT,SYMBUTT,19,49,70,10,10\n"
	"204,205,,ODEXIT,SYMBUTT,20,61,70,10,10\n"
	"205,206,,ODEXIT,SYMBUTT,21,73,70,10,10\n"
	"206,207,,ODEXIT,SYMBUTT,22,85,70,10,10\n"
	"207,208,,ODEXIT,SYMBUTT,23,97,70,10,10\n"
	"208,209,,ODEXIT,SYMBUTT,24,109,70,10,10\n"
	"209,,,CHECKED,CHECKBOX,25,25,50,80,9\n"
	"300,301,,TOUCHEXIT,RADIO1,13,20,35,80,9\n"
	"301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
	"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()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 60, 10, "Scheme"};
	TabSHEET tab3 = {60, 97, 10, "Symbols"};
	static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
	Symbol *syms[8], **lsyms;
	static DWORD defcol = 0x0L;
	char x_txt[100], y_txt[100];
	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*) &tab3, (void*)" draw symbols", (void*)&syms[0], (void*)&syms[1], (void*)&syms[2],
		(void*)&syms[3], (void*)&syms[4], (void*)&syms[5], (void*)&syms[6], (void*)&syms[7],
		(void*) " use line color for symbols"};
	DlgRoot *Dlg;
	void *hDlg;
	char **rdx=0L, **rdy=0L;
	DWORD *rdc = 0L, curr_col;
	int i, j, nd, res, currYR=0, maxYR=0, s1, s2, rx, ry, cx, cy;
	double symsize, x, y;
	bool updateYR = true, bContinue = false, bError, bRet = false;
	AccRange *rX = 0L, *rY = 0L;
	DataLine *dl;

	if(!parent || !data) return false;
	symsize = NiceValue(defs.GetSize(SIZE_SYMBOL)*.8);
	for(i = 0; i < 8; i++) if(syms[i] = new Symbol(0L, data, 0.0, 0.0, i)) {
		if(i != 2 && i != 3)syms[i]->SetSize(SIZE_SYMBOL, symsize);
		}
	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] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);			rdc[j] = colarr[j%8];	
			rdy[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);		maxYR = j++;
			}
		}
	if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
	hDlg = CreateDlgWnd("Create Multi Line Plot", 50, 50, 420, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(106, true);	Dlg->ShowItem(108, false);
				}
			else {
				Dlg->ShowItem(106, false);	Dlg->ShowItem(108, true);
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "x-range # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"x-range # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			Dlg->SetText(101, TmpTxt);
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-range # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-range # %d/%d", currYR+1, maxYR+1);
#endif
			Dlg->SetText(103, TmpTxt);
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(bContinue || Dlg->GetCheck(20)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 1:
		case 105:										//next button
			bError=false;	s1 = s2 = 0;
			if(Dlg->GetText(102, x_txt, 100)) {
				if(rX = new AccRange(x_txt)) {
					s1 = rX->CountItems();
					if(s1 < 2) {
						ErrorBox("x-range not valid");
						bContinue=bError=true;
						Dlg->Activate(102, true);
						}
					delete rX;
					}
				else bError = true;
				}
			else bError = true;
			if(Dlg->GetText(104, y_txt, 100) && !bError) {
				if(rY = new AccRange(y_txt)) {
					s2 = rY->CountItems();
					if(s2 < 2) {
						ErrorBox("y-range not valid");
						bContinue=bError=true;
						Dlg->Activate(104, true);
						}
					delete rY;
					}
				else bError = true;
				}
			else {
				Dlg->Activate(104, true);
				bError = true;
				}
			if(!s1 || !s2) bError = true;
			rX = rY = 0L;
			if(!bError && s1!=s2) {
				ErrorBox("X-range and y-range are\ndifferent in size");
				bContinue=bError=true;
				}
			if(!bError) {
				if((currYR+1) > maxYR) {
					rdx = (char**)realloc(rdx, sizeof(char*)*(currYR+2));
					rdy = (char**)realloc(rdy, sizeof(char*)*(currYR+2));
					rdc = (DWORD*)realloc(rdc, sizeof(DWORD)*(currYR+2));
					rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
					maxYR = currYR+1;
					rdc[currYR] = rdc[currYR+1] = Dlg->GetCheck(302) ? colarr[maxYR & 0x07] : defcol;
					}
				if(rdx[currYR]) free(rdx[currYR]);		//store x-range
				rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
				if(rdy[currYR]) free(rdy[currYR]);		//store y range
				rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
				Dlg->GetColor(107, &curr_col);			rdc[currYR] = curr_col;
				updateYR = true;						currYR++;
				Dlg->SetColor(107, rdc[currYR]);		Dlg->SetText(102, rdx[currYR]);
				Dlg->SetText(104, rdy[currYR]);			Dlg->Activate(102, true);				
				if(res != 1) res = -1;
				}
			else if(res != 1){
				bContinue = true;
				res = -1;
				}
			break;
		case 106:										//prev button
			if(Dlg->GetText(102, x_txt, 100) && Dlg->GetText(104, y_txt, 100)){
				if(rdx[currYR]) free(rdx[currYR]);		if(rdy[currYR]) free(rdy[currYR]);
				rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
				rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
				Dlg->GetColor(107, &curr_col);			rdc[currYR] = curr_col;
				}
			else if(currYR == maxYR) maxYR--;
			currYR--;
			Dlg->SetColor(107, rdc[currYR]);			Dlg->SetText(102, rdx[currYR]);
			Dlg->SetText(104, rdy[currYR]);				Dlg->Activate(102, true);
			updateYR = true;
			res = -1;
			break;
		case 201:	case 202:	case 203:	case 204:
		case 205:	case 206:	case 207:	case 208:
			res = -1;
		case 300:
			Dlg->SetColor(107, defcol);
			bContinue = true;
			res = -1;	break;
		case 301:
			Dlg->SetCheck(300, 0L, true);				Dlg->GetColor(res, &defcol);
			res = -1;	break;
		case 302:
			Dlg->SetColor(107, colarr[currYR & 0x07]);
			bContinue = true;
			res = -1;	break;
		case 303:	case 304:	case 305:	case 306:
		case 307:	case 308:	case 309:	case 310:
			Dlg->SetCheck(302, 0L, true);
			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);
	if(res == 1 && rdx && rdy && maxYR) {
		maxYR++;		rX = rY = 0L;
		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(Dlg->GetCheck(200) && (rX = new AccRange(rdx[i])) && (rY = new AccRange(rdy[i]))) {
					lsyms = (Symbol**)calloc(rX->CountItems()+1, sizeof(Symbol*));
					symsize = syms[i &0x07]->GetSize(SIZE_SYMBOL);
					for(nd = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry); rX->GetNext(&cx, &rx), rY->GetNext(&cy, &ry); ) {
						if(data->GetValue(rx, cx, &x) && data->GetValue(ry, cy, &y)) {
							lsyms[nd] = new Symbol(0L, data, x, y, syms[i &0x07]->type, cx, rx, cy, ry);
							if(Dlg->GetCheck(209)) lsyms[nd]->SetColor(COL_SYM_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0x07]);
							else {
								lsyms[nd]->SetColor(COL_SYM_LINE, syms[i &0x07]->GetColor(COL_SYM_LINE));
								lsyms[nd]->SetColor(COL_SYM_FILL, syms[i &0x07]->GetColor(COL_SYM_FILL));
								}
							lsyms[nd]->SetSize(SIZE_SYMBOL, symsize);
							nd++;
							}
						}
					}
				else {
					nd = 0;		lsyms = 0L;
					}
				if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
					dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0xf]);
					if(xyPlots[numXY] = new PlotScatt(this, data, nd, lsyms, dl)) {
						if(rY) xyPlots[numXY]->data_desc = rY->RangeDesc(data, 1);
						numXY++;
						}
					else delete dl;
					}
				if(rX)delete rX;		if(rY)delete rY;		rX = rY = 0L;
				}
			}
		if(numXY) bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rdx) {
		for (i = 0; i < maxYR; i++)	if(rdx[i]) free(rdx[i]);
		free(rdx);
		}
	if(rdy) {
		for (i = 0; i < maxYR; i++)	if(rdy[i]) free(rdy[i]);
		free(rdy);
		}
	for(i = 0; i < 8; i++) if(syms[i]) delete syms[i];
	free(StackBarDlg);		if(rdc) free(rdc);
	if(bRet) {
		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;	Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
		Command(CMD_AUTOSCALE, 0L, 0L);
		}
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Pie and ring chart properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *PieDlgTmpl = 
	"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,103\n"
	"5,6,200,ISPARENT,SHEET,2,5,10,120,103\n"
	"6,10,300,ISPARENT,SHEET,3,5,10,120,103\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"100,+,,,LTEXT,4,10,25,60,8\n"
	".,105,,,RANGEINPUT,-15,15,35,100,10\n"
	"105,.,500,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,,,EDVAL1,6,58,59,30,10\n"
	".,,,,LTEXT,-3,89,59,15,8\n" 
	"200,+,,,LTEXT,7,15,30,60,8\n"
	".,.,,,RTEXT,-4,2,42,20,8\n"
	".,204,,,EDVAL1,8,23,42,30,10\n"
	"204,.,,,RTEXT,-5,47,42,20,8\n"
	".,.,,,EDVAL1,9,68,42,30,10\n"
	".,.,,,LTEXT,-3,99,42,15,8\n" 
	".,.,,,RTEXT,10,27,58,20,8\n"
	".,.,,,EDVAL1,11,48,58,30,10\n"
	".,210,,,LTEXT,12,79,58,15,8\n" 
	"210,.,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	".,,,,LTEXT,-27,15,80,30,8\n"
	"300,,,NOSELECT,ODBUTTON,14,20,35,80,60\n"
	"400,+,,EXRADIO | CHECKED,ODBUTTON,15,55,75,30,30\n"
	".,,,EXRADIO,ODBUTTON,15,85,75,30,30\n"
	"410,+,,EXRADIO | CHECKED,ODBUTTON,15,55,75,30,30\n"
	".,,,EXRADIO,ODBUTTON,15,85,75,30,30\n"
	"500,+,,CHECKED,RADIO1,16,10,59,20,8\n"
	".,.,,,RADIO1,17,10,71,40,8\n"
	".,.,,,RANGEINPUT,-16,15,82,100,10\n"
	".,.,,,LTEXT,19,15,94,10,8\n"
	".,.,,,EDVAL1,20,42,94,25,10\n"
	".,,,,LTEXT,21,70,94,15,8\n"
	"600,+,,,RTEXT,22,8,59,45,8\n"
	".,.,,,RTEXT,23,8,74,45,8\n"
	".,.,,,EDVAL1,24,58,74,30,10\n"
	".,,,LASTOBJ,LTEXT,-3,89,74,15,8";
bool
PieChart::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Details"};
	TabSHEET tab3 = {55, 90, 10, "Scheme"};
	double fcx =10.0, fcy = 20.0, frad=40.0, firad = 30.0;
	char txt2[80];
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"spread sheet range for values",
		(void*)0L, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
		(void*)"start angle", (void*)&CtDef.fx, (void*)"degree", (void*)0L, (void*)(OD_scheme),
		(void*)(OD_PieTempl), (void*)"fixed radius", (void*)"pick radii from spreadsheet range",
		(void*)0L, (void*)"x  factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
		(void*)"inner radius", (void*)&firad};
	DlgInfo *PieDlg = CompileDialog(PieDlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int i, ix, iy, rix, riy, ny, res, cf, cb;
	bool bRet = false, bContinue = false;
	double sum = 0.0, dang1, dang2;
	double fv;
	lfPOINT fpCent;
	AccRange *rY = 0L, *rR = 0L;

	if(!parent || !data) return false;
	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
	cb = rlp_strcpy(txt2, 80, "= [");	cb += rlp_strcpy(txt2+cb, 80-cb, Units[defs.cUnits].display);
	rlp_strcpy(txt2+cb, 80-cb, "]");
	frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0;
	fcx = parent->GetSize(SIZE_GRECT_LEFT) + (parent->GetSize(SIZE_DRECT_LEFT))/2.0 + frad;
	fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
	firad = frad-frad/10.0f;
	if(!(Dlg = new DlgRoot(PieDlg, data)))return false;
	if(Id == GO_PIECHART) {
		Dlg->ShowItem(105, true);		Dlg->ShowItem(106, false);
		Dlg->ShowItem(210, true);		Dlg->ShowItem(211, false);
		}
	else {
		Dlg->ShowItem(105, false);		Dlg->ShowItem(106, true);
		Dlg->ShowItem(210, false);		Dlg->ShowItem(211, true);
		}
	hDlg = CreateDlgWnd(Id == GO_PIECHART ? (char*)"Create pie chart" : 
		(char*)"Create ring chart",	50, 50, 370, 266, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		//rY is defined by OK. If other buttons use rY reset to 0L!
		switch(res) {
		case 0:							//lost focus ?
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 400:	case 410:
			Dlg->SetText(208, "90");		Dlg->DoPlot(0L);
			CtDef.fy = 360.0;					res = -1;
			break;
		case 401:	case 411:
			Dlg->SetText(208, "180");		Dlg->DoPlot(0L);
			CtDef.fy = 180.0;					res = -1;
			break;
		case 1:
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
				ny = rY->CountItems();
			else ny = 0;
			Dlg->GetValue(208, &CtDef.fx);		Dlg->GetValue(202, &fcx);
			Dlg->GetValue(205, &fcy);			Dlg->GetValue(107, &frad);
			Dlg->GetValue(602, &firad);			Dlg->GetValue(504, &FacRad);
			if(Dlg->GetCheck(501) && ny && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE) && 
				(rR = new AccRange(TmpTxt))){
				if(rR->CountItems() != ny) {
					delete rR;
					delete rY;
					rR = rY = 0L;
					ErrorBox("Range for values and\nrange for radii must\nhave the same size!");
					bContinue = true;
					res = -1;
					}
				}
			break;
			}
		}while (res < 0);

	if(res == 1 && rY && ny >1 && (Segments = (segment **)calloc(ny, sizeof(segment*)))) {
		nPts = ny;
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssRefA = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
		if(rR && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE)) ssRefR = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
		Bounds.Xmax = Bounds.Ymax = 100.0;		Bounds.Xmin = Bounds.Ymin = -100.0;
		fpCent.fx = fcx;					fpCent.fy = fcy;
		rY->GetFirst(&ix, &iy);				rY->GetNext(&ix, &iy);
		for(i = 0; i < ny; i++){
			if(data->GetValue(iy, ix, &fv)) sum += fv;
			rY->GetNext(&ix, &iy);
			}
		sum /= CtDef.fy;
		dang1 = dang2 = CtDef.fx;
		rY->GetFirst(&ix, &iy);				rY->GetNext(&ix, &iy);
		if(rR) {
			rR->GetFirst(&rix, &riy);		rR->GetNext(&rix, &riy);
			}
		for(i = cf = 0; i < ny; i++){
			if(data->GetValue(iy, ix, &fv)) {
				dang2 -= (double)fv / sum;
				if(dang2 < 0.0) dang2 += 360.0;
				if(rR && data->GetValue(riy, rix, &frad)) frad *= FacRad;
				Segments[i] = new segment(this, data, &fpCent, 
					Id == GO_PIECHART ? 0.0 : firad, frad,
					dang1, dang2);
				if(Segments[i])Segments[i]->Command(CMD_SEG_FILL, GetSchemeFill(&cf), 0L);
				dang1 = dang2;
				}
			rY->GetNext(&ix, &iy);
			if(rR) rR->GetNext(&rix, &riy);
			}
		bRet = true;
		}
	if(rY) delete rY;		if(rR) delete rR;
	CloseDlgWnd(hDlg);		delete Dlg;				free(PieDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a star chart
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
StarChart::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Labels"};
	double sa = 90.0, factor = 1.0, lbdist = NiceValue(DefSize(SIZE_TEXT)*1.2);
	char txt1[80], txt2[80];
	DlgInfo StarDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
		{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, 103},
		{5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 103},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 30, 60, 8},
		{101, 102, 0, 0x0L, RANGEINPUT, txt1, 15, 45, 100, 10},
		{102, 103, 0, 0x0L, RTEXT, (void*)"x  factor", 17, 57, 30, 8},
		{103, 104, 0, 0x0L, EDVAL1, &factor, 48, 57, 30, 10},
		{104, 105, 0, 0x0L, LTEXT, &txt2, 79, 57, 15, 8},
		{105, 106, 0, 0x0L, RTEXT, (void*)"start angle", 17, 72, 30, 8},
		{106, 107, 0, 0x0L, EDVAL1, &sa, 48, 72, 30, 10},
		{107, 108, 0, 0x0L, LTEXT, (void*)"degree", 79, 72, 15, 8}, 
		{108, 109, 0, CHECKED, CHECKBOX, (void*)"draw polygon", 25, 87, 20, 8},
		{109, 0, 0, CHECKED, CHECKBOX, (void*)"draw rays", 25, 97, 20, 8},
		{200, 201, 0, 0x0L, CHECKBOX, (void*)"add labels to data points", 15, 28, 50, 8},
		{201, 202, 0, 0x0L, RANGEINPUT, (void*)txt1, 15, 51, 100, 10},
		{202, 203, 0, 0x0L, LTEXT, (void*)"spread sheet range for labels:", 15, 40, 60, 8},
		{203, 204, 0, 0x0L, RTEXT, (void*)"distance:", 10, 70, 40, 8},
		{204, 205, 0, 0x0L, EDVAL1, &lbdist, 52, 70, 30, 10},
		{205, 0, 0, LASTOBJ, LTEXT, (void*)Units[defs.cUnits].display, 85, 70, 10, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	int i, ix, iy, res, width, height, ny;
	bool bRet = false, bContinue = false;
	AccRange *rY = 0L, *rL = 0L;
	Label *lb;
	lfPOINT *fp = 0L, *fpt = 0L, fl[2];
	double fx, fy, tmpval, frad;
	double sia, csia;
	polyline *plo;
	TextDEF td = {0x00000000L, 0x00ffffffL, DefSize(SIZE_TEXT), 0.0, 0.0, 0,
		TXA_HCENTER | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L}; 

	if(!parent || !data) return false;
	data->GetSize(&width, &height);
#ifdef USE_WIN_SECURE
	sprintf_s(txt1, 80,"a1:a%d", height);	sprintf_s(txt2, 80, "= [%s]", Units[defs.cUnits].display);
#else
	sprintf(txt1, "a1:a%d", height);		sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
#endif
	if(parent) {
		frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
		fPos.fx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT) + frad;
		fPos.fy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
		}
	if(!(Dlg = new DlgRoot(StarDlg, data)))return false;
	hDlg = CreateDlgWnd("Create star chart", 50, 50, 370, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:							//lost focus ?
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 1:
			if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rY = new AccRange(TmpTxt))) 
				ny = rY->CountItems();
			else ny = 0;
			Dlg->GetValue(106, &sa);			Dlg->GetValue(103, &factor);
			Dlg->GetValue(204, &lbdist);
			break;
			}
		}while (res < 0);
	if(res == 1 && rY && ny >1 && (fp = (lfPOINT*)calloc(ny+1, sizeof(lfPOINT))) &&
		(fpt = (lfPOINT*)calloc(ny+1, sizeof(lfPOINT)))){
		Bounds.Xmax = Bounds.Ymax = 100.0;		Bounds.Xmin = Bounds.Ymin = -100.0;
		rY->GetFirst(&ix, &iy);
		for(i = 0; i < ny; i++){
			rY->GetNext(&ix, &iy);
			if(data->GetValue(iy, ix, &tmpval)){
				tmpval *= factor;
				sia = sin(sa * 0.01745329252);			csia = cos(sa * 0.01745329252);
				fx = (tmpval * csia);					fy = (-tmpval * sia);
				}
			else fx = fy = 0.0f;
			fp[i].fx = fpt[i].fx = fx;			fp[i].fy = fpt[i].fy = fy;
			fpt[i].fx += lbdist *csia;			fpt[i].fy += (-lbdist * sia);
			sa -= 360.0/ny;
			}
		fp[i].fx = fp[0].fx;		fp[i].fy = fp[0].fy;
		if(Dlg->GetCheck(108)){
			if((plo = new polygon(this, data, fp, ny+1))) {		//ny+1 to close the shape!
				if(!(bRet = Command(CMD_DROP_OBJECT, (void*)plo, 0L))) delete plo;
				}
			}
		if(Dlg->GetCheck(109)){
			fl[0].fx = fl[0].fy = 0.0f;
			for(i = 0; i < ny; i++) {
				fl[1].fx = fp[i].fx;		fl[1].fy = fp[i].fy;
				if((plo = new polyline(this, data, fl, 2))) {
					if(Command(CMD_DROP_OBJECT, (void*)plo, 0L)) bRet = true;
					else delete plo;
					}
				}
			}
		if(Dlg->GetCheck(200) && Dlg->GetText(201, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && (rL = new AccRange(TmpTxt))){
			rL->GetFirst(&ix, &iy);
			td.text = TmpTxt;
			for(i = 0; i < ny; i++) {
				rL->GetNext(&ix, &iy);
				if(data->GetText(iy, ix, TmpTxt, TMP_TXT_SIZE)){
					if((lb = new Label(this, data, fpt[i].fx, fpt[i].fy, &td, 0L))) {
						if(Command(CMD_DROP_OBJECT, (void*)lb, 0L)) bRet = true;
						else delete lb;
						}
					}
				}
			}
		}
	if(rY) delete rY;			if(rL) delete rL;
	if(fp) free(fp);			if(fpt) free(fpt);
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Grid3D represents a surface in space
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Grid3D::PropertyDlg()
{
	return Configure();
}

bool
Grid3D::Configure()
{
	TabSHEET tab1 = {0, 37, 10, "Function"};
	TabSHEET tab2 = {37, 65, 10, "Style"};
	FillDEF newFill;
	DlgInfo GridDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 50, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 50, 12},
		{3, 0, 300, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{300, 301, 500, HIDDEN | CHECKED, GROUPBOX, (void*)" grid lines ", 10, 10, 140, 100},
		{301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 10, 140, 100},
		{305, 306, 0, TOUCHEXIT, RADIO1, (void*) " grid lines", 155, 45, 50, 10},
		{306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 155, 57, 50, 10},
		{400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 20, 40, 8},
		{401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 20, 25, 10},
		{402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 20, 20, 8},
		{403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 32, 40, 8},
		{404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 32, 25, 10},
		{405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 44, 40, 8},
		{406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 44, 25, 10},
		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 15, 130, 100}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, cb, new_type, undo_level = *Undo.pcb;
	bool bRet = false;
	double tmp;
	DWORD new_col;
	LineDEF newLine;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	if(!(Dlg = new DlgRoot(GridDlg, data))) return false;
	if(!type) {
		Dlg->ShowItem(300, true);	Dlg->SetCheck(305, 0L, true);
		}
	else {
		Dlg->ShowItem(301, true);	Dlg->SetCheck(306, 0L, true);
		}
	if(parent->name) {
		cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Grid of ");
		rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
		}
	else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Grid");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 426, 260, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 305:		case 306:
			if(Dlg->GetCheck(305)) {
				Dlg->ShowItem(300, true);	Dlg->ShowItem(301, false);
				}
			else {
				Dlg->ShowItem(300, false);	Dlg->ShowItem(301, true);
				}
			Dlg->Command(CMD_REDRAW, 0L, 0L);
			res = -1;
			break;
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
	if(res == 1) {
		if(Dlg->GetCheck(305) && type == 0) {
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			if(cmpLineDEF(&Line, &newLine)) {
				Command(CMD_SET_LINE, &newLine, 0L);
				bRet = true;
				}
			}
		else if(Dlg->GetCheck(306) && type == 1) {
			Dlg->GetValue(401, &tmp);			Dlg->GetColor(404, &new_col);
			if(planes && (cmpFillDEF(&Fill, &newFill) || tmp != Line.width || new_col != Line.color)) {
				Command(CMD_SAVE_SYMBOLS, 0L, 0L);
				Command(CMD_SYM_FILL, &newFill, 0L);
				if(tmp != Line.width) SetSize(SIZE_SYM_LINE, tmp);
				if(new_col != Line.color) SetColor(COL_POLYLINE, new_col);
				bRet = true;
				}
			}
		else {
			Undo.ValInt(parent, &type, 0L);
			Undo.Line(this, &Line, UNDO_CONTINUE);	Undo.Fill(this, &Fill, UNDO_CONTINUE);
			if(Dlg->GetCheck(305)) {
				new_type = 0;
				OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
				}
			else {
				new_type = 1;
				memcpy(&Fill, &newFill, sizeof(FillDEF));
				Dlg->GetValue(401, &Line.width);
				Dlg->GetColor(404, &Line.color);
				Line.pattern = 0L;
				Line.patlength = 1;
				}
			if(planes && nPlanes) Undo.DropListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
			if(lines && nLines) Undo.DropListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
			Undo.VoidPtr(parent, (void**)&planes, 0L, 0L, UNDO_CONTINUE);
			Undo.VoidPtr(parent, (void**)&lines, 0L, 0L, UNDO_CONTINUE);
			type = new_type;
			CreateObs(true);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Scatt3D is a layer representing most simple 3D plots
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *Dlg3DTmpl = 
		"1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
		"2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
		"3,50,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
		"4,5,100,TOUCHEXIT | ISPARENT | CHECKED, SHEET,1,5,10,131,100\n"
		"5,6,200,TOUCHEXIT | ISPARENT, SHEET,2,5,10,131,100\n"
		"6,10,400, TOUCHEXIT | ISPARENT, SHEET,3,5,10,131,100\n"
		"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
		"50,60,,NOSELECT, ODBUTTON,4,142,65,45,45\n"
		"60,61,,,ICON,5,10,114,20,20\n"
		"61,62,,,LTEXT,6,30,116,100,6\n"
		"62,,,,LTEXT,7,30,122,100,6\n"
		"100,101,,,LTEXT,8,10,30,60,8\n"
		"101,102,,,RANGEINPUT,9,20,40,100,10\n"
		"102,103,,,LTEXT,10,10,55,60,8\n"
		"103,104,,,RANGEINPUT,11,20,65,100,10\n"
		"104,105,,,LTEXT,12,10,80,60,8\n"
		"105,,,,RANGEINPUT,13,20,90,100,10\n"
		"200,201,,,LTEXT,-27,25,30,60,8\n"
		"201,202,,,CHECKBOX,15,30,55,60,8\n"
		"202,203,,TOUCHEXIT,CHECKBOX,16,30,65,60,8\n"
		"203,204,,TOUCHEXIT,CHECKBOX,17,30,45,60,8\n"
		"204,205,,TOUCHEXIT,CHECKBOX,18,30,75,60,8\n"
		"205,,,TOUCHEXIT,CHECKBOX,19,30,85,60,8\n"
		"400,410,,,LTEXT,20,20,30,60,8\n"
		"410,411,,EXRADIO,ODBUTTON,21,20,42,25,25\n"
		"411,412,,EXRADIO,ODBUTTON,21,45,42,25,25\n"
		"412,,,LASTOBJ | EXRADIO,ODBUTTON,21,70,42,25,25";

bool
Scatt3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab2 = {22, 50, 10, "Layout"};
	TabSHEET tab3 = {50, 75, 10, "Axes"};
	char text1[100], text2[100], text3[100];
	int icon = ICO_INFO;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)(OD_AxisDesc3D), (void*)&icon,
		(void*)"Use [arrow keys], [shift]+[arrow key],", (void*)"and [r], [R], [l] or [L] to rotate graph.",
		(void*)"range for X Data", (void*)text1, (void*)"range for Y Data", (void*)text2,
		(void*)"range for Z Data", (void*)text3, (void*)0L, (void*)" balls", (void*)" columns",
		(void*)" line", (void*)" drop lines", (void*)" arrows", (void*)"select template:", 
		(void*)(OD_AxisTempl3D)};
	DlgInfo *Dlg3D = CompileDialog(Dlg3DTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int res, n1, n2, n3, ic = 0;
	int i, j, k, l, m, n, i2, j2, k2, l2, m2, cb;
	double x, y, z, bar_w, bar_d, rad;
	bool bRet = false, bContinue = false;
	AccRange *rX, *rY, *rZ;
	fPOINT3D pos1, pos2;

	if(!data || !parent)return false;
	UseRangeMark(data, 1, text1, text2, text3);
	if(!(Dlg = new DlgRoot(Dlg3D, data)))return false;
	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
	for(i = 0; i < 5; i++) Dlg->SetCheck(201+i, 0L, (c_flags & (1<<i))!=0);
	if(c_flags == 0x2000 || c_flags == 0x4000) {
		Dlg->ShowItem(5, false);		Dlg->ShowItem(6, false);
		}
	else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
	rX = rY = rZ = 0L;					rad = DefSize(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 Paravent Plot": 
	c_flags == 0x4000 ? (char*)"Delauney Surface" : (char*)"Create 3D Plot", 50, 50, 388, 300, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 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 410:	case 411:	case 412:	//axis templates
			AxisTempl3D = res-410;
			res = -1;
			break;
		case 1:
			if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
			rX = rY = rZ = 0L;	n1 = n2 = n3 = 0;
			if(Dlg->GetText(101, text1, 100) && (rX = new AccRange(text1))) n1 = rX->CountItems();
			if(Dlg->GetText(103, text2, 100) && (rY = new AccRange(text2))) n2 = rY->CountItems();
			if(Dlg->GetText(105, text3, 100) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
			if(n1 && n2 && n3){
				if(c_flags == 0x2000 || c_flags == 0x4000) {
					//no more but a ribbon or surface
					}
				else if(n1 == n2 && n2 == n3) {
					//o.k., three ranges of equal size have been defined
					c_flags = 0;
					for(i = 0; i < 5; i++) if(Dlg->GetCheck(201+i)) c_flags |= (1<<i);
					}
				else {
					InfoBox("All ranges must have\nthe same size."); 
					res = -1;	bContinue = true;
					}
				}
			else {
				cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ranges for ");
				if(!n1) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  X Data");
				if(!n2) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  Y Data");
				if(!n3) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n-  Z Data");
				rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\nnot given or not valid.");
				InfoBox(TmpTxt);
				res = -1;	bContinue = true;
				}
			break;
			}
		}while (res <0);
	if(res == 1 && rX && rY && rZ) {
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		bar_w = bar_d = (DefSize(SIZE_BAR)/2.0);
		if(c_flags & 0x01) (Balls = (Sphere**)calloc((nBalls = n1)+1, sizeof(Sphere*)));
		if(c_flags & 0x02) (Columns = (Brick**)calloc((nColumns = n1)+1, sizeof(Brick*)));
		if(c_flags & 0x04) Line = new Line3D(this, data, text1, text2, text3);
		if(c_flags & 0x08) (DropLines = (DropLine3D**)calloc((nDropLines = n1)+1, sizeof(DropLine3D*)));
		if(c_flags & 0x010) (Arrows = (Arrow3D**)calloc((nArrows = n1)+1, sizeof(Arrow3D*)));
		rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
		rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
		rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
		i2 = i;	j2 = j;	k2 = k;	l2 = l;	m2 = m;	n2 = n;
		if(c_flags == 0x2000){
			Bounds.Ymin = 0.0;
			rib = new Ribbon(this, data, 2, text1, text2, text3);
			}
		else if(c_flags == 0x4000){
			rib = new Ribbon(this, data, 3, text1, text2, text3);
			}
		do {
			if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && 
				data->GetValue(n, m, &z)){
				if(ic) {
					pos1.fx = pos2.fx;		pos1.fy = pos2.fy;	pos1.fz = pos2.fz;
					}
				else {
					pos1.fx = x;			pos1.fy = y;		pos1.fz = z;
					}
				pos2.fx = x;	pos2.fy = y;	pos2.fz = z;
				if(!bRet) memcpy(&pos1, &pos2, sizeof(fPOINT3D));
				if(Balls) Balls[ic] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
				if(Columns)Columns[ic] = new Brick(this, data, x, 0.0, z, 
					bar_d, bar_w, y, 0x800L, i, j, -1, -1, m, n, -1, -1, -1, -1, k, l);
				if(DropLines) DropLines[ic] = new DropLine3D(this, data, &pos2, i, j, k, l, m, n);
				if(Arrows) Arrows[ic] = new Arrow3D(this, data, &pos1, &pos2, 
					i, j, k, l, m, n, i2, j2, k2, l2, m2, n2);
				((Plot3D *)parent)->CheckBounds3D(x, y, z);		CheckBounds3D(x, y, z);
				bRet = true;
				}
			i2 = i;	j2 = j;	k2 = k;	l2 = l;	m2 = m;	n2 = n;
			ic++;
			}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
		if(!bRet) InfoBox("The selected data range\nis empty or does not contain\nvalid"
			" data triplets!");
		bRet = true;
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(Dlg3D);
	if(rX) delete rX;		if(rY) delete rY;	if(rZ) delete rZ;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// user defined function properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Function::PropertyDlg()
{
	TabSHEET tab1 = {0, 37, 10, "Function"};
	TabSHEET tab2 = {37, 60, 10, "Line"};
	DlgInfo FuncDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 32, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 32, 12},
		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 110},
		{5, 0, 500, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 110},
		{10, 600, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 24, 100, 8},
		{101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 40, 28, 8}, 
		{102, 103, 0, 0x0L, EDVAL1, &x1, 38, 40, 25, 10},
		{103, 104, 0, 0x0L, RTEXT, (void*)"until", 61, 40, 17, 8}, 
		{104, 105, 0, 0x0L, EDVAL1, &x2, 78, 40, 25, 10},
		{105, 106, 0, 0x0L, RTEXT, (void*)"step", 102, 40, 17, 8}, 
		{106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 40, 25, 10},
		{107, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 56, 10, 8}, 
		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 54, 122, 40},
		{500, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 45, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 60, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 75, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 90, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb;
	bool bRet = false, bNew = (dl == 0L);
	DWORD undo_flags = 0L;
	LineDEF newLine;
	double o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
	if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
	if(!bNew) Dlg->ShowItem(10, false);
	Dlg->GetValue(102, &o_x1);		n_x1 = o_x1;
	Dlg->GetValue(104, &o_x2);		n_x2 = o_x2;
	Dlg->GetValue(106, &o_xstep);	n_xstep = o_xstep;
	hDlg = CreateDlgWnd("Function Plot", 50, 50, 400, 276, Dlg, 0x4L);
	if(bNew) Dlg->SetCheck(4, 0L, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			break;
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	if(res == 2) while(*Undo.pcb > undo_level)	Undo.Restore(true, cdisp);
	else if(res == 1){					//OK pressed
		if(bNew) {						//create function
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
			Dlg->GetValue(106, &xstep);		Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
			cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
			ReshapeFormula(&cmdxy);			bRet = Update(0L, 0L);
			}
		else {							//edit existing function
			Dlg->GetValue(102, &n_x1);		Dlg->GetValue(104, &n_x2);
			Dlg->GetValue(106, &n_xstep);
			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE))
				undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
			if(undo_flags & UNDO_CONTINUE){
				Update(0L, UNDO_CONTINUE);		Command(CMD_MRK_DIRTY, 0L, 0L);
				}
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			if(cmpLineDEF(&Line, &newLine)) {
				Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
				memcpy(&Line, &newLine, sizeof(LineDEF));
				}
			bRet = (undo_flags & UNDO_CONTINUE) != 0;
			}
		}
	CloseDlgWnd(hDlg);		delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// fit function by nonlinear regression
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
FitFunc::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab2 = {22, 59, 10, "Function"};
	TabSHEET tab3 = {59, 82, 10, "Line"};
	char text1[100], text2[100];
	double iter;
	bool bNew = (dl == 0L);
	DlgInfo FuncDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 32, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 32, 12},
		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 125},
		{5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 125},
		{6, 7, 500, ISPARENT, SHEET, &tab3, 5, 10, 149, 125},
		{7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 123, 32, 12},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{100, 101, 0, 0x0L, LTEXT, (void*)"fit function by nonlinear regression", 10, 24, 100, 8},
		{101, 102, 0, 0x0L, LTEXT, (void*)"parameters and initial values:", 10, 34, 100, 8},
		{102, 150, 0, 0x0L, TEXTBOX, (void*)parxy, 22, 44, 122, 25},
		{150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x):", 10, 72, 10, 8}, 
		{151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 86, 10, 8}, 
		{152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 118, 26, 8}, 
		{153, 154, 0, 0x0L, EDVAL1, &conv, 46, 118, 25, 10},
		{154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 118, 47, 8}, 
		{155, 200, 0, 0x0L, EDVAL1, &iter, 119, 118, 25, 10},
		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 84, 122, 30},
		{400, 401, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
		{401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
		{402, 403, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
		{403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
		{404, 405, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 95, 60, 8},
		{405, 0, 0, HIDDEN, LTEXT, 0L, 20, 95, 60, 8},
		{500, 550, 501, CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{501, 502, 0, 0x0L, RTEXT, (void*)"plot x=", 10, 30, 28, 8}, 
		{502, 503, 0, 0x0L, EDVAL1, &x1, 38, 30, 25, 10},
		{503, 504, 0, 0x0L, RTEXT, (void*)"until", 61, 30, 17, 8}, 
		{504, 505, 0, 0x0L, EDVAL1, &x2, 78, 30, 25, 10},
		{505, 506, 0, 0x0L, RTEXT, (void*)"step", 102, 30, 17, 8}, 
		{506, 0, 0, 0x0L, EDVAL1, &xstep, 119, 30, 25, 10},
		{550, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, bNew ? 35:45, 130, 100}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb, i, j, k, l, cs;
	size_t cb;
	bool bRet = false, bContinue = false;
	DWORD undo_flags = 0L;
	LineDEF newLine;
	double tmp, tmpy, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2;
	AccRange *rX, *rY;
	char *o_cmdxy, *o_parxy, *tmp_char;
	anyOutput *cdisp = Undo.cdisp;
	anyResult *ares;

	if(!parent || !data) return false;
	if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0))) return false;;
	if(!(o_parxy = (char*)memdup(parxy, (int)strlen(parxy)+1, 0))) return false;;
	UseRangeMark(data, 1, text1, text2);
	iter = (double)maxiter;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
	if(!bNew){
		Dlg->ShowItem(10, false);		Dlg->Activate(401, false);
		Dlg->Activate(403, false);		Dlg->SetCheck(6, 0L, true);
		Dlg->SetCheck(4, 0L, false);	Dlg->ShowItem(404, false);
		if(chi2 > 0.0) {
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
#else
			sprintf(TmpTxt, "Chi 2 = %g", chi2);
#endif
			Dlg->SetText(405,TmpTxt);	Dlg->ShowItem(405, true);
			}
		}
	else {
		Dlg->ShowItem(500, false);
		}
	Dlg->GetValue(502, &o_x1);		n_x1 = o_x1;
	Dlg->GetValue(504, &o_x2);		n_x2 = o_x2;
	Dlg->GetValue(506, &o_xstep);	n_xstep = o_xstep;
	hDlg = CreateDlgWnd("Fit Function to Data", 50, 50, 400, 306, Dlg, 0x4L);
	if(bNew) Dlg->SetCheck(4, 0L, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			if(bContinue) res = -1;
			bContinue = false;
			break;
		case 1:
			if(!bNew){
				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
					if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
						rlp_strcpy(parxy, (int)cb, TmpTxt);
					}
				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
					if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
						rlp_strcpy(cmdxy, (int)cb, TmpTxt);
					}
				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
				dirty = true;
				break;
				}
		case 7:								//Start: do nonlinear regression
			Undo.SetDisp(cdisp);
			if(Dlg->GetCheck(5)) {			//  the function tab must be shown
				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
				Dlg->GetText(401, text1, 100);		Dlg->GetText(403, text2, 100);
				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
					if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
						rlp_strcpy(parxy, (int)cb, TmpTxt);
					}
				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
					if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
						rlp_strcpy(cmdxy, (int)cb, TmpTxt);
					}
				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
				do_formula(data, 0L);		//clear any error condition
				ares = do_formula(data, parxy);
				if(ares->type != ET_VALUE) {
					ErrorBox("Syntax Error in parameters.");
					bContinue = true;	res = -1;
					break;
					}
				ares = do_formula(data, cmdxy);
				if(ares->type != ET_VALUE) {
					ErrorBox("Syntax Error in formula.");
					bContinue = true;	res = -1;
					break;
					}
				i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, parxy);	i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;");
				rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy);	yywarn(0L, true);
				ares = do_formula(data, TmpTxt);
				if(tmp_char = yywarn(0L, false)) {
					ErrorBox(tmp_char);
					bContinue = true;	res = -1;
					break;
					}
				i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
				Dlg->SetText(102, parxy);
				if(i >1 || res == 7) {
#ifdef USE_WIN_SECURE
					sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
#else
					sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
#endif
					InfoBox(TmpTxt);
					}
				bContinue = true;
				if(res == 7) res = -1;
				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_ARROW, true);
				}
			else {							//diplay function tab first
				Dlg->SetCheck(5, 0L, true);
				res = -1;
				}
			break;
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
	if(res == 1){						//OK pressed
		//get ranges for x- and y data (again).
		chi2 = n_chi2;
		if(Dlg->GetText(401, text1, 100) && (ssXref = (char*)realloc(ssXref, (cb = strlen(text1)+2))))
			rlp_strcpy(ssXref, (int)cb, text1);
		if(Dlg->GetText(403, text2, 100) && (ssYref = (char*)realloc(ssYref, (cb = strlen(text2)+2))))
			rlp_strcpy(ssYref, (int)cb, text2);
		if(bNew) {						//create function
			if(!(rX = new AccRange(text1)) || ! (rY = new AccRange(text2))) return false;
			i = rX->CountItems();	maxiter = int(iter);
			if(Dlg->GetCheck(404)) Symbols = (Symbol**)calloc(i, sizeof(Symbol*));
			x1 = HUGE_VAL;	x2 = -HUGE_VAL;	cs = 0;
			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
			Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
			rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
			rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
			do {
				if(data->GetValue(j, i, &tmp) && data->GetValue(l, k, &tmpy)){
					if(tmp < x1) x1 = tmp;			if(tmp > x2) x2 = tmp;
					if(Symbols) Symbols[cs++] = new Symbol(this, data, tmp, tmpy, SYM_CIRCLE, i, j, k, l);
					nPoints = cs;					CheckBounds(tmp, tmpy);
					}
				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
			delete rX;	delete rY;
			if(x1 >= x2 || !(dl = new Function(this, data, "Fitted function"))){
				CloseDlgWnd(hDlg);
				delete Dlg;
				return false;
				}
			xstep = (x2 - x1)/100.0;
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
			dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
			dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
			dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
			dl->Command(CMD_AUTOSCALE, 0L, 0L);		CheckBounds(dl->Bounds.Xmin, dl->Bounds.Ymin);
			CheckBounds(dl->Bounds.Xmax, dl->Bounds.Ymax);
			Command(CMD_ENDDIALOG, 0L, 0L);			bRet = true;
			}
		else {							//edit existing function
			Dlg->GetValue(502, &n_x1);		Dlg->GetValue(504, &n_x2);
			Dlg->GetValue(506, &n_xstep);
			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
			if(undo_flags){
				dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
				dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
				dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
				dl->Update(0L, UNDO_CONTINUE);
				}
			undo_flags = CheckNewString(&parxy, o_parxy, parxy, this, undo_flags);
			undo_flags = CheckNewString(&cmdxy, o_cmdxy, cmdxy, this, undo_flags);
			if(undo_flags & UNDO_CONTINUE) {
				Undo.ValInt(parent, (int*)&dirty, undo_flags);
				Command(CMD_MRK_DIRTY, 0L, 0L);
				}
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			if(cmpLineDEF(&Line, &newLine)) {
				Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
				memcpy(&Line, &newLine, sizeof(LineDEF));
				}
			bRet = (undo_flags & UNDO_CONTINUE) != 0;
			Command(CMD_ENDDIALOG, 0L, 0L);
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(o_parxy) free(o_parxy);		if(o_cmdxy) free(o_cmdxy);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a new normal quantile plot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *NormQuantDlg_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,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";

bool
NormQuant::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	DlgInfo *QuantDlg;
	void *dyndata[] = {(void*)&tab1, (void*)"range for variables"};
	DlgRoot *Dlg;
	void *hDlg;
	int res;
	char *mrk;
	bool bContinue = false, bRet = false;

	if(!parent || !data) return false;
	if(!(QuantDlg = CompileDialog(NormQuantDlg_Tmpl, dyndata))) return false;
	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
	else UseRangeMark(data, 1, TmpTxt);
	if(!(Dlg = new DlgRoot(QuantDlg, data)))return false;
	hDlg = CreateDlgWnd("Normal Quantiles Plot", 50, 50, 420, 220, Dlg, 0x4L);
	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, TMP_TXT_SIZE)){
		ssRef = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
		bRet = ProcessData();
		}
	CloseDlgWnd(hDlg);	delete Dlg;	free(QuantDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Contour Plot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *ContourPlot_Tmpl = 
	"1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
	"2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,131,100\n"
	"5,6,200,ISPARENT,SHEET,5,5,10,131,100\n"
	"6,10,300,ISPARENT,SHEET,13,5,10,131,100\n"
	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
	"100,+,,,LTEXT,2,10,30,60,8\n"
	".,.,,,RANGEINPUT,-15,20,40,100,10\n"
	".,.,,,LTEXT,3,10,55,60,8\n"
	".,.,,,RANGEINPUT,-16,20,65,100,10\n"
	".,.,,,LTEXT,4,10,80,60,8\n"
	".,,,,RANGEINPUT,-17,20,90,100,10\n"
	"200,,201,CHECKED,GROUPBOX,6,10,30,121,70\n"
	".,+,,CHECKED,RADIO1,7,20,38,60,9\n"
	".,.,,,RADIO1,8,20,48,60,9\n"
	".,.,,,RADIO1,9,20,58,60,9\n"
	".,.,,,RADIO1,10,20,68,60,9\n"
	".,.,,,EDVAL1,11,50,78,30,10\n"
	".,,,,RTEXT,12,15,79,33,8\n"
	"300,310,301,CHECKED,GROUPBOX,14,10,30,121,55\n"
	".,+,,CHECKED,RADIO1,15,20,38,60,9\n"
	".,.,,,RADIO1,16,20,48,60,9\n"
	".,.,,,RADIO1,17,20,58,60,9\n"
	".,,,,RADIO1,18,20,68,60,9\n"
	"310,,,LASTOBJ,CHECKBOX,19,20,90,60,9";

bool
ContourPlot::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25,56, 10, "Details"};
	TabSHEET tab3 = {56,92, 10, "Symbols"};
	void *dyndata[] = {(void*)&tab1, (void*)"range for x-data", (void*)"range for y-data", 
		(void*)"range for z-data", (void*)&tab2, (void*)" super rectangle ", (void*)" at z minimum",
		(void*)" at z maximum", (void*)" at z mean", (void*)" at user defined level,", (void*)&sr_zval, (void*)"z =",
		(void*)&tab3, (void*)"  draw symbols  ", (void*)" no symbols", (void*)" draw minima", (void*)" draw maxima",
		(void*)" draw all source data", (void*)" symbols with labels"};
	DlgInfo *DlgInf;
	DlgRoot *Dlg;
	void *hDlg;
	int res;
	bool bRet = false, bContinue = false;

	if(!data || !parent)return false;
	if(!(DlgInf = CompileDialog(ContourPlot_Tmpl, dyndata)))return false;
	UseRangeMark(data, 1, TmpTxt, TmpTxt+100, TmpTxt+200);
	if(!(Dlg = new DlgRoot(DlgInf, data)))return false;
	hDlg = CreateDlgWnd((char*)"Create Contour Plot", 50, 50, 388, 260, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			else if(Dlg->GetCheck(10)) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 1:
			res = -1;		bContinue = false;
			if(Dlg->GetCheck(202))flags = 0x01;
			else if(Dlg->GetCheck(203))flags = 0x02;
			else if(Dlg->GetCheck(204)){
				flags = 0x03;	Dlg->GetValue(205, &sr_zval);
				}
			else flags = 0x00;
			if(Dlg->GetCheck(302)) flags |= 0x10;
			else if(Dlg->GetCheck(303)) flags |= 0x20;
			else if(Dlg->GetCheck(304)) flags |= 0x30;
			if(Dlg->GetCheck(310)) flags |= 0x40;
			if(Dlg->GetText(101, TmpTxt, 100) && Dlg->GetText(103, TmpTxt+100, 100) 
				&& Dlg->GetText(105, TmpTxt+200, 100)){
				if(LoadData(TmpTxt, TmpTxt+100, TmpTxt+200)) {
					ssRefX = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
					ssRefY = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
					ssRefZ = (char*)memdup(TmpTxt+200, (int)strlen(TmpTxt+200)+1, 0);
					res = 1;		bRet = true;
					}
				}
			if(res != 1) {
				bContinue = true;
				ErrorBox("Missing or too\nfew data\n");
				}
			break;
			}
		}while (res <0);
	CloseDlgWnd(hDlg);		delete Dlg;			free(DlgInf);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a three dimensional graph
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *AddAxis3D_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,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,148\n"
		"5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,148\n"
		"6,20,300,ISPARENT,SHEET,3,5,10,130,148\n"
		"20,,,NOSELECT,ODBUTTON,22,142,65,45,45\n"
		"50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
		"51,120,,,CHECKBOX,5,17,37,80,8\n"
		"100,101,,,RTEXT,6,10,51,35,8\n"
		"101,102,,,EDVAL1,7,48,51,32,10\n"
		"102,103,,,CTEXT,8,81,51,11,8\n"
		"103,,,,EDVAL1,9,93,51,32,10\n"
		"120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
		"121,122,,,RTEXT,11,10,77,25,8\n"
		"122,123,,,EDVAL1,12,37,77,25,10\n"
		"123,124,,,LTEXT,-3,63,77,10,8\n"
		"124,125,,,RTEXT,-11,73,77,25,8\n"
		"125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
		"130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
		"131,,,,EDTEXT,0,15,103,110,10\n"
		"200,201,,,LTEXT,16,10,23,70,9\n"
		"201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,35,25,25\n"
		"202,203,,EXRADIO,ODBUTTON,17,45,35,25,25\n"
		"203,204,,EXRADIO,ODBUTTON,17,70,35,25,25\n"
		"204,205,,EXRADIO,ODBUTTON,17,95,35,25,25\n"
		"205,206,,EXRADIO,ODBUTTON,17,20,60,25,25\n"
		"206,207,,EXRADIO,ODBUTTON,17,45,60,25,25\n"
		"207,208,,EXRADIO,ODBUTTON,17,70,60,25,25\n"
		"208,209,,EXRADIO,ODBUTTON,17,95,60,25,25\n"
		"209,210,,EXRADIO,ODBUTTON,17,20,85,25,25\n"
		"210,211,,EXRADIO,ODBUTTON,17,45,85,25,25\n"
		"211,212,,EXRADIO,ODBUTTON,17,70,85,25,25\n"
		"212,213,,EXRADIO,ODBUTTON,17,95,85,25,25\n"
		"213,214,,,LTEXT,-12,20,120,70,9\n"
		"214,215,,,LTEXT,-13,20,132,70,9\n"
		"215,216,,,LTEXT,-14,20,144,70,9\n"
		"216,217,250,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
		"217,218,260,HIDDEN | ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
		"218,,270,HIDDEN |ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
		"250,251,,,LTEXT,19,10,110,70,9\n"
		"251,252,,,EDVAL1,0,58,120,32,10\n"
		"252,253,,,LTEXT,-3,92,120,20,9\n"
		"253,254,,,EDVAL1,0,43,132,32,10\n"
		"254,255,,,CTEXT,-7,75,132,7,9\n"
		"255,256,,,EDVAL1,0,82,132,32,10\n"
		"256,257,,,LTEXT,-3,116,132,20,9\n"
		"257,268,,,EDVAL1,0,58,144,32,10\n"
		"260,261,,,LTEXT,20,10,110,70,9\n"
		"261,262,,,EDVAL1,0,43,120,32,10\n"
		"262,263,,,CTEXT,-7,75,120,7,9\n"
		"263,264,,,EDVAL1,0,82,120,32,10\n"
		"264,265,,,LTEXT,-3,116,120,20,9\n"
		"265,266,,,EDVAL1,0,58,132,32,10\n"
		"266,267,,,LTEXT,-3,92,132,20,9\n"
		"267,268,,,EDVAL1,0,58,144,32,10\n"
		"268,,,,LTEXT,-3,92,144,20,9\n"
		"270,271,,,LTEXT,21,10,110,70,9\n"
		"271,272,,,EDVAL1,0,58,120,32,10\n"
		"272,273,,,LTEXT,-3,92,120,20,9\n"
		"273,274,,,EDVAL1,0,58,132,32,10\n"
		"274,275,,,LTEXT,-3,92,132,20,9\n"
		"275,276,,,EDVAL1,0,43,144,32,10\n"
		"276,277,,,CTEXT,-7,75,144,7,9\n"
		"277,278,,,EDVAL1,0,82,144,32,10\n"
		"278,,,,LTEXT,-3,116,144,20,9\n"
		"300,,,LASTOBJ | NOSELECT,ODBUTTON,18,15,30,110,140";
bool
Plot3D::AddAxis()
{
	TabSHEET tab1 = {0, 25, 10, "Axis"};
	TabSHEET tab2 = {25, 52, 10, "Style"};
	TabSHEET tab3 = {52, 78, 10, "Plots"};
	AxisDEF axis, ax_def[12], *caxdef;
	double sizAxLine = DefSize(SIZE_AXIS_LINE);
	DWORD colAxis = 0x0;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
		(void*)"axis from", (void*)&axis.min, (void*)"to", (void*)&axis.max, (void*)" line ", (void*)"width",
		(void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
		(void*)(OD_NewAxisTempl3D), (void*)OD_axisplot, (void*)"y-axis at:", (void*)"x-axis at:", (void*)"z-axis at:",
		(void*)(OD_AxisDesc3D)};
	DlgInfo *NewAxisDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, res, currTempl = 201, ax_type = 2, tick_type = 2;
	double tlb_dx, tlb_dy, lb_x, lb_y;
	TextDEF label_def, tlbdef;
	anyOutput *cdisp = Undo.cdisp;
	Axis *the_new, **tmpAxes;
	bool bAxis = false, bRet = false;
	char **names;
	GraphObj **somePlots;
	Label *label;

	if(!Axes || nAxes < 3 || !(NewAxisDlg = CompileDialog(AddAxis3D_Tmpl, dyndata))) return false;
	lb_y = 0.0;		lb_x = DefSize(SIZE_AXIS_TICKS)*4.0;
	tlb_dy = 0.0;	tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
	tlbdef.ColTxt = colAxis;				tlbdef.ColBg = 0x00ffffffL;
	tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
	tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
	tlbdef.Style = TXS_NORMAL;				tlbdef.Mode = TXM_TRANSPARENT;
	tlbdef.Font = FONT_HELVETICA;			tlbdef.text = 0L;
	if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
	if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
	for(i = 0; i < 12; i++) {
		ax_def[i].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK;
		ax_def[i].owner = 0L;		ax_def[i].breaks = 0L;
		ax_def[i].Center.fx = ax_def[i].Center.fy = ax_def[i].Radius = 0.0;
		ax_def[i].nBreaks = 0L;
		}
	//y-axes
	ax_def[0].min = ax_def[1].min = ax_def[2].min = ax_def[3].min = (caxdef = Axes[1]->GetAxis())->min;
	ax_def[0].max = ax_def[1].max = ax_def[2].max = ax_def[3].max = caxdef->max;
	ax_def[0].Start = ax_def[1].Start = ax_def[2].Start = ax_def[3].Start = caxdef->Start;
	ax_def[0].Step = ax_def[1].Step = ax_def[2].Step = ax_def[3].Step = caxdef->Step;
	ax_def[0].loc[0].fy  = ax_def[1].loc[0].fy = ax_def[2].loc[0].fy = ax_def[3].loc[0].fy = caxdef->loc[0].fy;
	ax_def[0].loc[1].fy  = ax_def[1].loc[1].fy = ax_def[2].loc[1].fy = ax_def[3].loc[1].fy = caxdef->loc[1].fy;
	ax_def[0].loc[0].fx = ax_def[0].loc[1].fx = ax_def[3].loc[0].fx = ax_def[3].loc[1].fx = cu1.fx;
	ax_def[1].loc[0].fx = ax_def[1].loc[1].fx = ax_def[2].loc[0].fx = ax_def[2].loc[1].fx = cu2.fx;
	ax_def[0].loc[0].fz = ax_def[0].loc[1].fz = ax_def[1].loc[0].fz = ax_def[1].loc[1].fz = cu2.fz;
	ax_def[2].loc[0].fz = ax_def[2].loc[1].fz = ax_def[3].loc[0].fz = ax_def[3].loc[1].fz = cu1.fz;
	ax_def[1].flags = ax_def[2].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
	ax_def[0].flags = ax_def[3].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
	//x-axes
	ax_def[4].min = ax_def[6].min = ax_def[8].min = ax_def[10].min = (caxdef = Axes[0]->GetAxis())->min;
	ax_def[4].max = ax_def[6].max = ax_def[8].max = ax_def[10].max = caxdef->max;
	ax_def[4].Start = ax_def[6].Start = ax_def[8].Start = ax_def[10].Start = caxdef->Start;
	ax_def[4].Step = ax_def[6].Step = ax_def[8].Step = ax_def[10].Step = caxdef->Step;
	ax_def[4].loc[0].fx  = ax_def[6].loc[0].fx = ax_def[8].loc[0].fx = ax_def[10].loc[0].fx = caxdef->loc[0].fx;
	ax_def[4].loc[1].fx  = ax_def[6].loc[1].fx = ax_def[8].loc[1].fx = ax_def[10].loc[1].fx = caxdef->loc[1].fx;
	ax_def[4].loc[0].fy = ax_def[4].loc[1].fy = ax_def[6].loc[0].fy = ax_def[6].loc[1].fy = cu1.fy;
	ax_def[8].loc[0].fy = ax_def[8].loc[1].fy = ax_def[10].loc[0].fy = ax_def[10].loc[1].fy = cu2.fy;
	ax_def[4].loc[0].fz = ax_def[4].loc[1].fz = ax_def[8].loc[0].fz = ax_def[8].loc[1].fz = cu2.fz;
	ax_def[6].loc[0].fz = ax_def[6].loc[1].fz = ax_def[10].loc[0].fz = ax_def[10].loc[1].fz = cu1.fz;
	ax_def[4].flags = ax_def[6].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
	ax_def[8].flags = ax_def[10].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
	//z-axes
	ax_def[5].min = ax_def[7].min = ax_def[9].min = ax_def[11].min = (caxdef = Axes[2]->GetAxis())->min;
	ax_def[5].max = ax_def[7].max = ax_def[9].max = ax_def[11].max = caxdef->max;
	ax_def[5].Start = ax_def[7].Start = ax_def[9].Start = ax_def[11].Start = caxdef->Start;
	ax_def[5].Step = ax_def[7].Step = ax_def[9].Step = ax_def[11].Step = caxdef->Step;
	ax_def[5].loc[0].fz  = ax_def[7].loc[0].fz = ax_def[9].loc[0].fz = ax_def[11].loc[0].fz = caxdef->loc[0].fz;
	ax_def[5].loc[1].fz  = ax_def[7].loc[1].fz = ax_def[9].loc[1].fz = ax_def[11].loc[1].fz = caxdef->loc[1].fz;
	ax_def[5].loc[0].fx = ax_def[5].loc[1].fx = ax_def[9].loc[0].fx = ax_def[9].loc[1].fx = cu2.fx;
	ax_def[7].loc[0].fx = ax_def[7].loc[1].fx = ax_def[11].loc[0].fx = ax_def[11].loc[1].fx = cu1.fx;
	ax_def[5].loc[0].fy = ax_def[5].loc[1].fy = ax_def[7].loc[0].fy = ax_def[7].loc[1].fy = cu1.fy;
	ax_def[9].loc[0].fy = ax_def[9].loc[1].fy = ax_def[11].loc[0].fy = ax_def[11].loc[1].fy = cu2.fy;
	ax_def[5].flags = ax_def[9].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
	ax_def[7].flags = ax_def[11].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
	//the default axis is the first
	memcpy(&axis, &ax_def[0], sizeof(AxisDEF));
	if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
	for(i = 0, j = 1; i < nscp; i++) {
		if(Sc_Plots[i] && Sc_Plots[i]->name){
			names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
			somePlots[j++] = Sc_Plots[i];
			}
		}
	OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
	if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
	Dlg->SetValue(251, ax_def[0].loc[0].fx);		Dlg->SetValue(253, ax_def[0].loc[0].fy);
	Dlg->SetValue(255, ax_def[0].loc[1].fy);		Dlg->SetValue(257, ax_def[0].loc[0].fz);
	if(!nscp){						//must be root plot3d to link to plot
		Dlg->ShowItem(6, false);
		}
	hDlg = CreateDlgWnd("Add Axis to 3D Plot", 50, 50, 400, 360, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res){
		case 4:											//the axis sheet
			res = -1;
			bAxis = true;
			break;
		//axis templates
		case 201:	case 202:	case 203:	case 204:	case 205:	case 206:
		case 207:	case 208:	case 209:	case 210:	case 211:	case 212:
			i = currTempl-201;
			switch(currTempl){
				case 201:	case 202:	case 203:	case 204:		//prevoius is y-template
					Dlg->GetValue(251, &axis.loc[0].fx);	Dlg->GetValue(253, &axis.loc[0].fy);
					Dlg->GetValue(255, &axis.loc[1].fy);	Dlg->GetValue(257, &axis.loc[0].fz);
					axis.loc[1].fx = axis.loc[0].fx;		axis.loc[1].fz = axis.loc[0].fz;
					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
					break;
				case 205:	case 207:	case 209:	case 211:		//prevoius is x-template
					Dlg->GetValue(261, &axis.loc[0].fx);	Dlg->GetValue(263, &axis.loc[1].fx);
					Dlg->GetValue(265, &axis.loc[0].fy);	Dlg->GetValue(267, &axis.loc[0].fz);
					axis.loc[1].fy = axis.loc[0].fy;		axis.loc[1].fz = axis.loc[0].fz;
					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
					break;
				case 206:	case 208:	case 210:	case 212:		//previous is z-template
					Dlg->GetValue(271, &axis.loc[0].fx);	Dlg->GetValue(273, &axis.loc[0].fy);
					Dlg->GetValue(275, &axis.loc[0].fz);	Dlg->GetValue(277, &axis.loc[1].fz);
					axis.loc[1].fx = axis.loc[0].fx;		axis.loc[1].fy = axis.loc[0].fy;
					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
					break;
				}
			i = res-201;
			switch (res) {
			case 201:	case 202:	case 203:	case 204:			//y-template
				Dlg->ShowItem(216, true);		Dlg->ShowItem(217, false);
				Dlg->ShowItem(218, false);
				Dlg->SetValue(251, ax_def[i].loc[0].fx);	Dlg->SetValue(253, ax_def[i].loc[0].fy);
				Dlg->SetValue(255, ax_def[i].loc[1].fy);	Dlg->SetValue(257, ax_def[i].loc[0].fz);
				ax_type = tick_type = 2;	tlb_dy = 0.0;
				if(res == 202 || res == 203){
					tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
					}
				else {
					tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
					}
				break;
			case 205:	case 207:	case 209:	case 211:			//x-template
				Dlg->ShowItem(216, false);		Dlg->ShowItem(217, true);
				Dlg->ShowItem(218, false);
				Dlg->SetValue(261, ax_def[i].loc[0].fx);	Dlg->SetValue(263, ax_def[i].loc[1].fx);
				Dlg->SetValue(265, ax_def[i].loc[0].fy);	Dlg->SetValue(267, ax_def[i].loc[0].fz);
				ax_type = 1;	tick_type = 3; tlb_dx = 0;
				if(res == 205 || res == 207){
					tlb_dy = DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VTOP | TXA_HCENTER;
					}
				else {
					tlb_dy = -DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
					}
				break;
			case 206:	case 208:	case 210:	case 212:			//z-template
				Dlg->ShowItem(216, false);		Dlg->ShowItem(217, false);
				Dlg->ShowItem(218, true);
				Dlg->SetValue(271, ax_def[i].loc[0].fx);	Dlg->SetValue(273, ax_def[i].loc[0].fy);
				Dlg->SetValue(275, ax_def[i].loc[0].fz);	Dlg->SetValue(277, ax_def[i].loc[1].fz);
				ax_type = 3;	tick_type = 2;	tlb_dy = 0;
				if(res == 206 || res == 210){
					tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
					}
				else {
					tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
					tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
					}
				break;
				}
			memcpy(&axis, &ax_def[res-201], sizeof(AxisDEF));
			currTempl = res;
			Dlg->DoPlot(0L);
			res = -1;
			break;
			}
		}while (res < 0);
	if(res == 1) {
		Undo.SetDisp(cdisp);
		Dlg->GetValue(122, &sizAxLine);				Dlg->GetColor(125, &colAxis);
		Dlg->GetValue(101, &axis.min);				Dlg->GetValue(103, &axis.max);
		axis.Start = axis.min;						axis.Center.fx = axis.Center.fy = 0.0;
		axis.nBreaks = 0;			axis.breaks = 0L;		axis.Radius = 0.0;	
		tlbdef.ColTxt =	colAxis;
		label_def.ColTxt = colAxis;					label_def.ColBg = 0x00ffffffL;
		label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2f;	label_def.RotBL = 0.0f;
		label_def.RotCHAR = 0.0f;								label_def.iSize = 0;
		label_def.Align = TXA_VTOP | TXA_HCENTER;		label_def.Mode = TXM_TRANSPARENT;
		label_def.Style = TXS_NORMAL;	label_def.Font = FONT_HELVETICA;
		if(Dlg->GetCheck(51)) axis.flags |= AXIS_AUTOSCALE;
		if(the_new = new Axis(this, data, &axis, axis.flags)){
			the_new->SetSize(SIZE_TLB_YDIST, tlb_dy);	the_new->SetSize(SIZE_TLB_XDIST, tlb_dx); 
			the_new->SetSize(SIZE_AXIS_LINE, sizAxLine);
			the_new->SetColor(COL_AXIS, colAxis);
			the_new->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
			the_new->SetSize(SIZE_LB_XDIST, lb_x);		the_new->SetSize(SIZE_LB_YDIST, lb_y);
			the_new->type = ax_type;
			the_new->Command(CMD_TICK_TYPE, &tick_type, 0L);
			if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) label_def.text = TmpTxt;
			else label_def.text = 0L;
			if(label = new Label(Axes[0], data, (axis.loc[0].fx + axis.loc[1].fx)/2.0,
				(axis.loc[0].fy + axis.loc[1].fy)/2.0, &label_def, 
				label_def.RotBL < 45.0 ? LB_Y_PARENT : LB_X_PARENT)){
				label->SetSize(SIZE_LB_XDIST, lb_x);	label->SetSize(SIZE_LB_YDIST, lb_y); 
				if(the_new->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
				else DeleteGO(label);
				}
			for(i = 0; i < nAxes && Axes[i]; i++);
			if(i < nAxes) {
				Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
				bRet = true;
				}
			else {
				if(tmpAxes = (Axis**)calloc(nAxes+1, sizeof(Axis*))){
					memcpy(tmpAxes, Axes, nAxes * sizeof(Axis*));
					Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, nAxes);
					Undo.SetGO(this, (GraphObj**)(&tmpAxes[nAxes]), the_new, 0L);
					free(Axes);			Axes = tmpAxes;
					i = nAxes++;		bRet = true;
					}
				}
			CurrAxes = Axes;
			if(bRet) {
				OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
				if(res && i) somePlots[res]->Command(CMD_USEAXIS, &i, 0L);
				}
			}
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(NewAxisDlg);
	if(names) {
		for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
		free(names);
		}
	if(somePlots) free(somePlots);
	return bRet;
}

static char *AddPlot3Dtmpl =
		"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
		"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
		"3,,560,ISPARENT | CHECKED,GROUPBOX,1,5,10,140,70\n"
		"560,561,,EXRADIO | CHECKED,ODBUTTON,2,12,20,25,25\n"
		"561,562,,EXRADIO,ODBUTTON,2,37,20,25,25\n"
		"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,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)
{
	void *dyndata[] = {(void *)"  select template  ", (void*)(OD_PlotTempl)};
	DlgInfo *PlotsDlg = CompileDialog(AddPlot3Dtmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int res, cSel = 560;
	bool bRet = false;
	Plot *p;

	if(!(Dlg = new DlgRoot(PlotsDlg, data)))return false;
	Dlg->bModal = false;
	hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 204, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		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;
				}
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		switch (cSel) {
		case 560:		p = new Scatt3D(this, data, 0x01);			break;
		case 561:		p = new Scatt3D(this, data, 0x02);			break;
		case 562:		p = new Scatt3D(this, data, 0x04);			break;
		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()) {
			if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) delete p;
			}
		else if(p) delete p;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(PlotsDlg);
	return bRet;
}

bool
Plot3D::PropertyDlg()
{
	Plot *p;
	bool bRet = false;

	if(plots) {
		//plots already created - jump to configuration dialog
		return false;
		}
	if((p = new Scatt3D(this, data, crea_flags)) && p->PropertyDlg()) {
		if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) DeleteGO(p);
		}
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a 2.5 dimensional bar chart
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *Base25D_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,,,PUSHBUTTON,-8,95,87,30,12\n"
		"156,,,,PUSHBUTTON,-9,60,87,35,12\n"
		"200,201,,,LTEXT,7,20,35,80,8\n"
		"201,202,,,RTEXT,8,48,45,13,8\n"
		"202,203,,,EDVAL1,9,65,45,25,10\n"
		"203,204,,,RTEXT,10,48,57,13,8\n"
		"204,,,,EDVAL1,11,65,57,25,10\n"
		"300,301,,,RADIO1,12,15,35,80,9\n"
		"301,302,,ODEXIT,COLBUTT,13,110,35,20,10\n"
		"302,303,,CHECKED,RADIO1,14,15,55,80,9\n"
		"303,304,,ODEXIT,COLBUTT,15,25,70,10,10\n"
		"304,305,,ODEXIT,COLBUTT,16,37,70,10,10\n"
		"305,306,,ODEXIT,COLBUTT,17,49,70,10,10\n"
		"306,307,,ODEXIT,COLBUTT,18,61,70,10,10\n"
		"307,308,,ODEXIT,COLBUTT,19,73,70,10,10\n"
		"308,309,,ODEXIT,COLBUTT,20,85,70,10,10\n"
		"309,310,,ODEXIT,COLBUTT,21,97,70,10,10\n"
		"310,,,LASTOBJ | ODEXIT,COLBUTT,22,109,70,10,10";
bool
Chart25D::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Details"};
	TabSHEET tab3 = {55, 90, 10, "Scheme"};
	static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
	static DWORD defcol = 0x00ffffffL;
	double start_z = 1.0;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
		(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],
		(void*)&colarr[7]};
	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	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;
	Brick **cols;
	Scatt3D *plot;
	AxisDEF *ax;

	if(!parent || !data) return false;
	if(plots) {
		//Plots alredy defined: jump to config dialog
		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++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
			}
		if(j) maxYR = j-1;
		}
	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
	if(!(Dlg = new DlgRoot(Bar3D_Dlg, data))) return false;
	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
	hDlg = CreateDlgWnd("Create 3D Bar Chart", 50, 50, 420, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(156, true);
				Dlg->Activate(101, false);
				}
			else {
				Dlg->ShowItem(156, false);
				Dlg->Activate(101, true);
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			Dlg->SetText(153, TmpTxt);
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		ny = 0;
		if(rX) delete rX;
		rX = 0L;
		switch(res) {
		case 0:
			if(bContinue || Dlg->GetCheck(20)) res = -1;
			break;
		case -1:
			bContinue = false;			break;
		case 1:
			for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
			Dlg->GetColor(301, &defcol);
			bUseSch = Dlg->GetCheck(302);
			Dlg->GetValue(202, &start_z);	Dlg->GetValue(204, &dspm.fz);
			//execute com_StackDlg for <OK>
		case 155:		case 156:
			res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			break;
		case 301:
			Dlg->SetCheck(300, 0L, true);
			res = -1;	break;
		case 303:	case 304:	case 305:	case 306:
		case 307:	case 308:	case 309:	case 310:
			Dlg->SetCheck(302, 0L, true);
			res = -1;	break;
			}
		}while (res < 0);
	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
		if(rd[maxYR]) maxYR++;
		fsz = DefSize(SIZE_BAR)/2.0;	fz = start_z;
		oax = AxisTempl3D;	AxisTempl3D = 1;	CreateAxes();
		if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
			ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
			ax->min = start_z-dspm.fz;
			ax->max = start_z+dspm.fz*maxYR;
			if(Axes[1] && (ax = Axes[1]->GetAxis())){
				ax->flags |= AXIS_GRIDLINE;
				i = 0x0c;
				Axes[1]->Command(CMD_SET_GRIDTYPE, &i, 0L);
				}
			AxisTempl3D = oax;
			}
		if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
			for(i = 0; i < maxYR; i++, fz += dspm.fz) {
				if(rd[i] && (cols = (Brick**)calloc(nx, sizeof(Brick*))) && (rY = new AccRange(rd[i]))) {
					ic = 0;
					if(rX->GetFirst(&cx, &rx) && rX->GetNext(&cx, &rx) &&
						rY->GetFirst(&cy, &ry) && rY->GetNext(&cy, &ry)) {
						do {
							if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)){
								cols[ic] = new Brick(this, data, fx, 0.0, fz, 
									fsz, fsz, fy, 0x800L, cx, rx, -1, -1, -1, -1,
									-1, -1, -1, -1, cy, ry);
								}
							ic++;
							}while(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry));
						if(ic) bRet = true;
						}
					if(plot = new Scatt3D(this, data, cols, ic)){
						if(bUseSch) plot->SetColor(COL_BAR_FILL, colarr[(i & 0x07)]);
						else plot->SetColor(COL_BAR_FILL, defcol);
						plots[nPlots++] = plot;
						}
					if(rY) {
						plot->data_desc = rY->RangeDesc(data, 1);
						delete(rY);		rY = 0L;
						}
					}
				}
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rd) {
		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
		free(rd);
		}
	if(rX) delete rX;		if(rY) delete rY;		free(Bar3D_Dlg);
	if(bRet) Command(CMD_MRK_DIRTY, 0L, 0L);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a 2.5 dimensional ribbon chart
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Ribbon25D::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Data"};
	TabSHEET tab2 = {25, 55, 10, "Details"};
	TabSHEET tab3 = {55, 90, 10, "Scheme"};
	static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
	static DWORD defcol = 0x00ffffffL;
	double start_z = 1.0;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
		(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],
		(void*)&colarr[7]};
	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, res, currYR=0, maxYR=0, nx=0, ny, oax;
	char **rd = 0L, xrange[100];
	double fz;
	bool updateYR = true, bContinue = false, bRet = false, bUseSch;
	AccRange *rX = 0L, *rY = 0L;
	AxisDEF *ax;
	Ribbon *plot;

	if(!parent || !data) return false;
	if(plots) {
		//Plots alredy defined: jump to config dialog
		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++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
			}
		if(j) maxYR = j-1;
		}
	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
	if(!(Dlg = new DlgRoot(Bar3D_Dlg, data)))return false;
	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
	hDlg = CreateDlgWnd("Create 3D Ribbon Chart", 50, 50, 420, 260, Dlg, 0x4L);
	do {
		if(updateYR) {
			if(currYR >0) {
				Dlg->ShowItem(156, true);		Dlg->Activate(101, false);
				}
			else {
				Dlg->ShowItem(156, false);		Dlg->Activate(101, true);
				}
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
#else
			sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
#endif
			//SetText will also cause a redraw of the whole dialog
			Dlg->SetText(153, TmpTxt);
			updateYR = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		ny = 0;		if(rX) delete rX;		rX = 0L;
		switch(res) {
		case 0:
			if(bContinue || Dlg->GetCheck(20)) res = -1;
			break;
		case -1:
			bContinue = false;			break;
		case 1:
			for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
			Dlg->GetColor(301, &defcol);	bUseSch = Dlg->GetCheck(302);
			Dlg->GetValue(202, &start_z);	Dlg->GetValue(204, &dspm.fz);
			//execute com_StackDlg for <OK>
		case 155:		case 156:
			res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
				&rY, &bContinue, &ny, &maxYR, &updateYR);
			break;
		case 301:
			Dlg->SetCheck(300, 0L, true);
			res = -1;	break;
		case 303:	case 304:	case 305:	case 306:
		case 307:	case 308:	case 309:	case 310:
			Dlg->SetCheck(302, 0L, true);
			res = -1;	break;
			}
		}while (res < 0);
	if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
		if(rd[maxYR]) maxYR++;					fz = start_z;
		Dlg->GetText(101, TmpTxt+100, 100);
		oax = AxisTempl3D;	AxisTempl3D = 1;	CreateAxes();
		if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
			ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
			ax->min = start_z-dspm.fz;
			ax->max = start_z+dspm.fz*maxYR;
			if(Axes[1] && (ax = Axes[1]->GetAxis())){
				ax->flags |= AXIS_GRIDLINE;	
				i = 0x0c;
				Axes[1]->Command(CMD_SET_GRIDTYPE, &i, 0L);
				}
			AxisTempl3D = oax;
			}
		if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
			Dlg->GetText(101, xrange, 100);
			for(i = 0; i < maxYR; i++, fz += dspm.fz) {
				if(plot = new Ribbon(this, data, fz, dspm.fz, xrange, rd[i])){
					if(bUseSch) plot->SetColor(COL_POLYGON, colarr[(i & 0x07)]);
					else plot->SetColor(COL_POLYGON, defcol);
					plots[nPlots++] = plot;
					}
				}
			}
		Command(CMD_MRK_DIRTY, 0L, 0L);		Command(CMD_AUTOSCALE, 0L, 0L);
		bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rd) {
		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
		free(rd);
		}
	if(rX) delete rX;		if(rY) delete rY;		free(Bar3D_Dlg);
	if(bRet) Command(CMD_MRK_DIRTY, 0L, 0L);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a 3 dimensional bubble plot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
BubblePlot3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab3 = {22, 47, 10, "Axes"};
	char text1[100], text2[100], text3[100], text4[100];
	DlgInfo BubDlg3D[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 142, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 142, 25, 45, 12},
		{3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 142},
		{5, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 142},
		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 142, 65, 45, 45},
		{100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 25, 60, 8},
		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 35, 100, 10},
		{102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 48, 60, 8},
		{103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 58, 100, 10},
		{104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 71, 60, 8},
		{105, 106, 0, 0x0L, RANGEINPUT, text3, 20, 81, 100, 10},
		{106, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" diameter ", 8, 98, 125, 50},
		{150, 151, 0, 0x0L, LTEXT, (void*)"range for diameters", 12, 102, 60, 8},
		{151, 152, 0, 0x0L, RANGEINPUT, text4, 20, 112, 100, 10},
		{152, 153, 0, 0x0L, LTEXT, (void*)"scaling:", 12, 125, 20, 8},
		{153, 154, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)Units[defs.cUnits].display, 38, 125, 20, 8},
		{154, 155, 0, TOUCHEXIT, RADIO1, (void*)"with x-values", 70, 125, 20, 8},
		{155, 156, 0, TOUCHEXIT, RADIO1, (void*)"with y-values", 20, 135, 20, 8},
		{156, 0, 0, TOUCHEXIT, RADIO1, (void*)"with z-values", 70, 135, 20, 8},
		{400, 410, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
		{410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
		{411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
		{412, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25}};
	DlgRoot *Dlg;
	void *hDlg;
	int i, res, count;
	int cx, rx, cy, ry, cz, rz, cr, rr, s_type = 5;
	bool bRet = false;
	double fx, fy, fz, fr;
	Sphere **Balls;
	AccRange *rX, *rY, *rZ, *rR;
	Scatt3D *sc_plot;

	if(!data || !parent)return false;
	UseRangeMark(data, 1, text1, text2, text3, text4);
	if(!(Dlg = new DlgRoot(BubDlg3D, data)))return false;
	rX = rY = rZ = rR = 0L;
	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
	hDlg = CreateDlgWnd("Bubble Plot 3D", 50, 50, 388, 340, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			break;
		case 4:		case 5:					//the tab sheets
			res = -1;
			break;
		case 153:	
			s_type = 5;						//absolute size, but use 5 to distinguish
			res = -1;						//  from symbol
			break;
		case 154:	case 155:	case 156:
			s_type = res - 153;
			res = -1;
			break;
		case 410:	case 411:	case 412:	//axis templates
			AxisTempl3D = res-410;
			res = -1;
			break;
			}
		}while (res <0);
	if(res == 1) {
		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
		if(Dlg->GetText(105, TmpTxt, TMP_TXT_SIZE)) rZ = new AccRange(TmpTxt);
		if(Dlg->GetText(151, TmpTxt, TMP_TXT_SIZE)) rR = new AccRange(TmpTxt);
		if(rX && rY && rZ && rR && (count = rX->CountItems()) 
			&& (Balls = (Sphere**)calloc(count, sizeof(Sphere*)))) {
			rX->GetFirst(&cx, &rx);		rY->GetFirst(&cy, &ry);
			rZ->GetFirst(&cz, &rz);		rR->GetFirst(&cr, &rr);
			for(i = 0; i < count; i++){
				if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry)
					&& rZ->GetNext(&cz, &rz) && rR->GetNext(&cr, &rr)
					&& data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)
					&& data->GetValue(rz, cz, &fz) && data->GetValue(rr, cr, &fr)) {
					Balls[i] = new Sphere(this, data, s_type, fx, fy, fz, fr, cx, rx,
						cy, ry, cz, rz, cr, rr);
					}
				}
			sc_plot = new Scatt3D(this, data, Balls, count);
			if(parent->Id == GO_PLOT3D || parent->Id == GO_FUNC3D || parent->Id == GO_FITFUNC3D) {
				if(!(parent->Command(CMD_DROP_PLOT, sc_plot, 0L))) delete(sc_plot);
				bRet = true;
				}
			else if(!(bRet = Command(CMD_DROP_PLOT, sc_plot, 0L))) delete(sc_plot);
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;	if(rR) delete rR;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a 3D function plot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Func3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 37, 10, "Function"};
	TabSHEET tab2 = {37, 65, 10, "Style"};
	FillDEF newFill;
	DlgInfo FuncDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 134},
		{5, 50, 300, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 134},
		{10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
		{50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 85, 45, 45},
		{100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 30, 100, 8},
		{101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 50, 28, 8}, 
		{102, 103, 0, 0x0L, EDVAL1, &x1, 38, 50, 25, 10},
		{103, 104, 0, 0x0L, RTEXT, (void*)"until", 61, 50, 17, 8}, 
		{104, 105, 0, 0x0L, EDVAL1, &x2, 78, 50, 25, 10},
		{105, 106, 0, 0x0L, RTEXT, (void*)"step", 102, 50, 17, 8}, 
		{106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 50, 25, 10},
		{107, 108, 0, 0x0L, RTEXT, (void*)"z=", 10, 62, 28, 8}, 
		{108, 109, 0, 0x0L, EDVAL1, &z1, 38, 62, 25, 10},
		{109, 110, 0, 0x0L, EDVAL1, &z2, 78, 62, 25, 10},
		{110, 150, 0, 0x0L, EDVAL1, &zstep, 119, 62, 25, 10},
		{150, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8}, 
		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 40},
		{300, 301, 500, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
		{301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
		{305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
		{306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
		{400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
		{401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
		{402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
		{403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
		{404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
		{405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
		{406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 45, 130, 100}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb;
	bool bRet = false, bNew = true;
	DWORD undo_flags = 0L;
	LineDEF newLine;
	double o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep;
	double o_z1, n_z1, o_z2, n_z2, o_zstep, n_zstep;
	anyOutput *cdisp = Undo.cdisp;

	if(!parent) return false;
//	if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
	if(!bNew) Dlg->ShowItem(10, false);
	Dlg->GetValue(102, &o_x1);		n_x1 = o_x1;
	Dlg->GetValue(104, &o_x2);		n_x2 = o_x2;
	Dlg->GetValue(106, &o_xstep);	n_xstep = o_xstep;
	Dlg->GetValue(108, &o_z1);		n_z1 = o_z1;
	Dlg->GetValue(109, &o_z2);		n_z2 = o_z2;
	Dlg->GetValue(110, &o_zstep);	n_zstep = o_zstep;
	hDlg = CreateDlgWnd("3D Function Plot", 50, 50, 426, 328, Dlg, 0x4L);
	if(bNew) Dlg->SetCheck(4, 0L, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 305:		case 306:
			if(Dlg->GetCheck(305)) {
				Dlg->ShowItem(300, true);	Dlg->ShowItem(301, false);
				}
			else {
				Dlg->ShowItem(300, false);	Dlg->ShowItem(301, true);
				}
			Dlg->DoPlot(0L);
			res = -1;
			break;
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			break;
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
	if(res == 1){						//OK pressed
		if(bNew) {						//create function
			if(Dlg->GetCheck(305)) {
				type = 0;
				OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
				}
			else {
				type = 1;
				memcpy(&Fill, &newFill, sizeof(FillDEF));
				Dlg->GetValue(401, &Line.width);
				Dlg->GetColor(404, &Line.color);
				Line.pattern = 0L;
				Line.patlength = 1;
				}
			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
			Dlg->GetValue(106, &xstep);
			Dlg->GetValue(108, &z1);		Dlg->GetValue(109, &z2);
			Dlg->GetValue(110, &zstep);		type = Dlg->GetCheck(305) ? 0 : 1;
			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
				if(cmdxy) free(cmdxy);		cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
				ReshapeFormula(&cmdxy);		bRet = Update();
				}
			}
		else {							//edit existing function
			Dlg->GetValue(102, &n_x1);		Dlg->GetValue(104, &n_x2);
			Dlg->GetValue(106, &n_xstep);
			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
			TmpTxt[0] = 0;	Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
			undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
//			if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			if(cmpLineDEF(&Line, &newLine)) {
				Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
				memcpy(&Line, &newLine, sizeof(LineDEF));
				}
			bRet = (undo_flags & UNDO_CONTINUE) != 0;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Fit a 3D function to data
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
FitFunc3D::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab2 = {22, 59, 10, "Function"};
	TabSHEET tab3 = {59, 87, 10, "Style"};
	char text1[100], text2[100], text3[100];
	FillDEF newFill;
	double iter;
//	bool bNew = (dl == 0L);
	bool bNew = true;
	DlgInfo FuncDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 134},
		{5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 134},
		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 149, 134},
		{7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 132, 45, 12},
		{10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
		{50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 65, 45, 45},
		{100, 101, 0, 0x0L, LTEXT, (void*)"fit function by nonlinear regression", 10, 24, 100, 8},
		{101, 102, 0, 0x0L, LTEXT, (void*)"parameters and initial values:", 10, 34, 100, 8},
		{102, 150, 0, 0x0L, TEXTBOX, (void*)param, 22, 44, 122, 30},
		{150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x,z):", 10, 77, 10, 8}, 
		{151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8}, 
		{152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 128, 26, 8}, 
		{153, 154, 0, 0x0L, EDVAL1, &conv, 46, 128, 25, 10},
		{154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 128, 47, 8}, 
		{155, 200, 0, 0x0L, EDVAL1, &iter, 119, 128, 25, 10},
		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 30},
		{300, 301, 550, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
		{301, 305, 350, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
		{305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
		{306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
		{350, 351, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
		{351, 352, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
		{352, 353, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
		{353, 354, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
		{354, 355, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
		{355, 356, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
		{356, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
		{400, 401, 0, 0x0L, LTEXT, (void*)"range for X data", 10, 30, 60, 8},
		{401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
		{402, 403, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 55, 60, 8},
		{403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
		{404, 405, 0, 0x0L, LTEXT, (void*)"range for Z data", 10, 80, 60, 8},
		{405, 406, 0, 0x0L, RANGEINPUT, (void*)text3, 20, 90, 100, 10},
		{406, 407, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 110, 60, 8},
		{407, 0, 0, HIDDEN, LTEXT, 0L, 20, 110, 60, 8},
		{500, 550, 501, CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{501, 502, 0, 0x0L, RTEXT, (void*)"plot x=", 10, 30, 28, 8}, 
		{502, 503, 0, 0x0L, EDVAL1, &x1, 38, 30, 25, 10},
		{503, 504, 0, 0x0L, RTEXT, (void*)"until", 61, 30, 17, 8}, 
		{504, 505, 0, 0x0L, EDVAL1, &x2, 78, 30, 25, 10},
		{505, 506, 0, 0x0L, RTEXT, (void*)"step", 102, 30, 17, 8}, 
		{506, 0, 0, 0x0L, EDVAL1, &xstep, 119, 30, 25, 10},
		{550, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, bNew ? 45:45, 130, 100}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, undo_level = *Undo.pcb, i, j, k, l, m, n, ns = 0;
	bool bRet = false, bContinue = false;
	DWORD undo_flags = 0L;
	LineDEF newLine;
	double x, y, z, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2, rad;
	AccRange *rX, *rY, *rZ;
	char *o_cmdxy, *o_param, *tmp_char;
	anyOutput *cdisp = Undo.cdisp;
	anyResult *ares;
	Sphere **Balls;

	if(!parent || !data) return false;
	UseRangeMark(data, 1, text1, text2, text3);
	if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0)))return false;
	if(!(o_param = (char*)memdup(param, (int)strlen(param)+1, 0)))return false;
	rX = rY = rZ = 0L;			iter = (double)maxiter;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
	memcpy(&newFill, &Fill, sizeof(FillDEF));
	memcpy(&newLine, &Line, sizeof(LineDEF));
	if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
	if(!bNew){
		Dlg->ShowItem(10, false);		Dlg->Activate(401, false);
		Dlg->Activate(403, false);		Dlg->Activate(405, false);		
		Dlg->SetCheck(6, 0L, true);
		Dlg->SetCheck(4, 0L, false);	Dlg->ShowItem(404, false);
		if(chi2 > 0.0) {
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
#else
			sprintf(TmpTxt, "Chi 2 = %g", chi2);
#endif
			Dlg->SetText(405,TmpTxt);	Dlg->ShowItem(405, true);
			}
		}
	else Dlg->ShowItem(500, false);
	Dlg->GetValue(502, &o_x1);		n_x1 = o_x1;
	Dlg->GetValue(504, &o_x2);		n_x2 = o_x2;
	Dlg->GetValue(506, &o_xstep);	n_xstep = o_xstep;
	hDlg = CreateDlgWnd("Fit Function to Data in 3D Space", 50, 50, 426, 328, Dlg, 0x4L);
	if(bNew) Dlg->SetCheck(4, 0L, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:
			if(Dlg->GetCheck(10)) res = -1;
			if(bContinue) res = -1;
			bContinue = false;
			break;
		case 305:		case 306:
			if(Dlg->GetCheck(305)) {
				Dlg->ShowItem(300, true);	Dlg->ShowItem(301, false);
				}
			else {
				Dlg->ShowItem(300, false);	Dlg->ShowItem(301, true);
				}
			Dlg->DoPlot(0L);
			res = -1;
			break;
		case 1:
			if(!bNew){
				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
					if(param) free(param);	
					param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
					}
				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
					if(cmdxy) free(cmdxy);	
					cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
					}
				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
				dirty = true;
				break;
				}
		case 7:								//Start: do nonlinear regression
			Undo.SetDisp(cdisp);
			if(!Dlg->GetText(401, text1, 100) || !Dlg->GetText(403, text2, 100) || !Dlg->GetText(405, text3, 100)) {
				Dlg->SetCheck(4, 0L, true);			bContinue = true;
				InfoBox("Invalid or missing range");
				res = -1;
				}
			else if(Dlg->GetCheck(5)) {		//  the function tab must be shown
				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
				if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
					if(param) free(param);	
					param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
					}
				if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
					if(cmdxy) free(cmdxy);	
					cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
					}
				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
				do_formula(data, 0L);		//clear any error condition
				ares = do_formula(data, param);
				if(ares->type != ET_VALUE) {
					ErrorBox("Syntax Error in parameters.");
					bContinue = true;	res = -1;
					break;
					}
				ares = do_formula(data, cmdxy);
				if(ares->type != ET_VALUE) {
					ErrorBox("Syntax Error in formula.");
					bContinue = true;	res = -1;
					break;
					}
				i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, param);	i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;z=1;");
				rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy);	yywarn(0L, true);
				ares = do_formula(data, TmpTxt);
				if(tmp_char = yywarn(0L, false)) {
					ErrorBox(tmp_char);
					bContinue = true;	res = -1;
					break;
					}
				i = do_fitfunc(data, text1, text2, text3, &param, cmdxy, conv, (int)iter, &chi2);
				Dlg->SetText(102, param);
				if(i >1 || res == 7) {
#ifdef USE_WIN_SECURE
					sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
#else
					sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
#endif
					InfoBox(TmpTxt);
					}
				bContinue = true;
				if(res == 7) res = -1;
				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_ARROW, true);
				}
			else {							//diplay function tab first
				Dlg->SetCheck(5, 0L, true);
				res = -1;
				}
			break;
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
	if(res == 1 && (rX=new AccRange(text1)) && (rY=new AccRange(text2)) && (rZ=new AccRange(text3))){
		//OK pressed
		if(bNew) {						//create function
			if(Dlg->GetCheck(305)) {
				type = 0;
				OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
				}
			else {
				type = 1;
				memcpy(&Fill, &newFill, sizeof(FillDEF));
				Dlg->GetValue(401, &Line.width);
				Dlg->GetColor(404, &Line.color);
				Line.pattern = 0L;			Line.patlength = 1;
				}
			rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
			rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
			rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
			do {
				if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z))
					CheckBounds3D(x,y,z);
				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
			x1 = xBounds.fx;		x2 = xBounds.fy;		xstep = (x2-x1)/10.0;
			z1 = zBounds.fx;		z2 = zBounds.fy;		zstep = (z2-z1)/10.0;
			if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
				if(param) free(param);	
				param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
				}
			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
				if(cmdxy) free(cmdxy);	
				cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
				}
			ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
			if((bRet = Update()) && gob && nPlots == 1 && (Balls=(Sphere**)calloc(rX->CountItems(), sizeof(Sphere*)))) {
				rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
				rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
				rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
				rad = DefSize(SIZE_SYMBOL);
				do {
					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z)) {
						Balls[ns++] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
						}
					}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
				if(ns) {
					plots[1] = (GraphObj*) new Scatt3D(this, data, Balls, ns);
					nPlots = 2;
					}
				else free(Balls);
				}
			if(bRet)Command(CMD_ENDDIALOG, 0L, 0L);
			}
		else {							//edit existing function
			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
			Dlg->GetValue(106, &xstep);
			Dlg->GetValue(108, &z1);		Dlg->GetValue(109, &z2);
			Dlg->GetValue(110, &zstep);		type = Dlg->GetCheck(305) ? 0 : 1;
			InfoBox("Not Implemented");
			}
		}
	if(rX) delete(rX);		if(rY) delete(rY);		if(rZ) delete(rZ);
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Grid line properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *GridLineDlg_Tmpl =
	"1,+,,DEFAULT,PUSHBUTTON, 1,150,10,50,12\n"
	".,.,,,PUSHBUTTON,2,150,25,50,12\n"
	".,10,,,PUSHBUTTON,-2,150,40,50,12\n"
	"10,,100,ISPARENT | CHECKED,GROUPBOX,3,5,10,139,123\n"
	"100,+,,NOSELECT,ODBUTTON,4,10,18,130,100\n"
	".,.,112,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,115,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,120,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
	".,.,125,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
	".,,130,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
	"111,,,,RTEXT,5,15,117,23,8\n"
	"112,+,,,CHECKBOX,-20,41,117,25,8\n"
	".,.,,,CHECKBOX,-21,105,117,25,8\n"
	".,111,,,CHECKBOX,-25,70,117,25,8\n"
	"115,+,,,CHECKBOX,-22,41,117,25,8\n"
	".,.,,,CHECKBOX,-23,105,117,25,8\n"
	".,111,,,CHECKBOX,-24,70,117,25,8\n"
	"120,+,,,CHECKBOX,-24,55,117,25,8\n"
	".,135,,,CHECKBOX,-25,90,117,25,8\n"
	"125,+,,,CHECKBOX,-24,55,117,25,8\n"
	".,135,,,CHECKBOX,-26,90,117,25,8\n"
	"130,+,,,CHECKBOX,-25,55,117,25,8\n"
	".,135,,,CHECKBOX,-26,90,117,25,8\n"
	"135,,,LASTOBJ,LTEXT,6,15,117,55,8";
bool
GridLine::PropertyDlg()
{
	TabSHEET tab1 = {0, 21, 10, "Line"};
	int dh = ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL))? -20 : 0;
	void *dyndata[] = {(void*)"Apply to LINE", (void*)"Apply to AXIS", (void*)" grid line ", 
		(void*)OD_linedef, (void*)"line to:", (void*)"parallel to:"}; 
	DlgInfo *LineDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int res, tmptype;
	bool bRet = false;
	DWORD undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	LineDEF newLine;

	if(!parent || !parent->parent) return false;
	if(!(LineDlg = CompileDialog(GridLineDlg_Tmpl, dyndata)))return false;
	LineDlg[3].h += dh;
	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
	if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
	if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
		//no checkboxes, changed sizes
		}
	else if(flags &AXIS_3D) {
		Dlg->SetCheck(120, 0L, type & 0x01 ? true : false);
		Dlg->SetCheck(121, 0L, type & 0x02 ? true : false);
		Dlg->SetCheck(125, 0L, type & 0x04 ? true : false);
		Dlg->SetCheck(126, 0L, type & 0x08 ? true : false);
		Dlg->SetCheck(130, 0L, type & 0x10 ? true : false);
		Dlg->SetCheck(131, 0L, type & 0x20 ? true : false);
		switch(parent->parent->type) {
		case 1:	Dlg->ShowItem(105, true);	break;
		case 2:	Dlg->ShowItem(104, true);	break;
		case 3: Dlg->ShowItem(103, true);	break;
			}
		}
	else {
		Dlg->SetCheck(112, 0L, type & DL_LEFT ? true : false);
		Dlg->SetCheck(113, 0L, type & DL_RIGHT ? true : false);
		Dlg->SetCheck(114, 0L, type & DL_YAXIS ? true : false);
		Dlg->SetCheck(115, 0L, type & DL_TOP ? true : false);
		Dlg->SetCheck(116, 0L, type & DL_BOTTOM ? true : false);
		Dlg->SetCheck(117, 0L, type & DL_XAXIS ? true : false);
		if(type & 0x07) Dlg->ShowItem(101, true);
		else Dlg->ShowItem(102, true);
		}
	hDlg = CreateDlgWnd("Grid line properties", 50, 50, 415, 310 + dh*2, Dlg, 0x4L);
	do{												//dh*2 means dh * ybase
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 1:							//this line
		case 2:							//all lines of plot
			Undo.SetDisp(cdisp);
			if(flags &AXIS_3D) {
				tmptype = 0;
				if(Dlg->GetCheck(120)) tmptype |= 0x01;		if(Dlg->GetCheck(121)) tmptype |= 0x02;
				if(Dlg->GetCheck(125)) tmptype |= 0x04;		if(Dlg->GetCheck(126)) tmptype |= 0x08;
				if(Dlg->GetCheck(130)) tmptype |= 0x10;		if(Dlg->GetCheck(131)) tmptype |= 0x20;
				}
			else {
				tmptype = (type & ~0xff);
				if(Dlg->GetCheck(112)) tmptype |= DL_LEFT;		if(Dlg->GetCheck(113)) tmptype |= DL_RIGHT;
				if(Dlg->GetCheck(114)) tmptype |= DL_YAXIS;		if(Dlg->GetCheck(115)) tmptype |= DL_TOP;
				if(Dlg->GetCheck(116)) tmptype |= DL_BOTTOM;	if(Dlg->GetCheck(117)) tmptype |= DL_XAXIS;
				}
			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
			break;
			}
		}while (res < 0);
	if(res == 1){			//Apply to line
		undo_flags = CheckNewInt(&type, type, tmptype, parent, undo_flags);
		if(cmpLineDEF(&LineDef, &newLine)) {
			Undo.Line(parent, &LineDef, undo_flags);	undo_flags |= UNDO_CONTINUE;
			memcpy(&LineDef, &newLine, sizeof(LineDEF));
			}
		if(undo_flags & UNDO_CONTINUE) bRet = bModified = true;
		}
	else if(res == 2) {		//Apply to axis
		if(parent->Id == GO_TICK && parent->parent->Id == GO_AXIS &&
			(tmptype != type || cmpLineDEF(&LineDef, &newLine))) {
			parent->parent->Command(CMD_SAVE_TICKS, 0L, 0L);
			if(cmpLineDEF(&LineDef, &newLine)) parent->parent->Command(CMD_SET_GRIDLINE, (void*)&newLine, 0L);
			if(tmptype != type) parent->parent->Command(CMD_SET_GRIDTYPE, (void*)(& tmptype), 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);	delete Dlg;		free(LineDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tick properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *TickDlg_Tmpl =
	"1,2,,,PUSHBUTTON,1,120,10,60,12\n"
	"2,3,,DEFAULT, PUSHBUTTON,2,120,25,60,12\n"
	"3,4,,,PUSHBUTTON,-2,120,40,60,12\n"
	"4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,110,100\n"
	"6,7,200,ISPARENT,SHEET,4,5,10,110,100\n"
	"7,,300,ISPARENT,SHEET,5,5,10,110,100\n"
	"100,101,,,RTEXT,6,10,30,35,8\n"
	"101,102,,,EDVAL1,7,50,30,25,10\n"
	"102,103,,,LTEXT,-3,77,30,20,8\n"
	"103,104,,,CHECKBOX,8,18,45,30, 8\n"
	"104,105,,,LTEXT,9,18,60,20,8\n"
	"105,106,,,RADIO1,0,40,70,35,8\n"
	"106,107,,,RADIO1,0,40,60,35,8\n"
	"107,108,,,RADIO1,10,40,80,35,8\n"
	"108,,,,CHECKBOX,11,18,95,30,8\n"
	"200,201,,,RTEXT,12,10,35,23,8\n"
	"201,202,,,EDVAL1,13,40,35,65,10\n"
	"202,203,,,LTEXT,14,15,55,20,8\n"
	"203,,,,EDTEXT,0,15,67,90,10\n"
	"300,301,,,LTEXT,15,15,30,70,8\n"
	"301,302,,TOUCHEXIT,RADIO1,16,15,42,70,8\n"
	"302,303,,TOUCHEXIT,RADIO1,17,15,52,70,8\n"
	"303,304,,TOUCHEXIT,RADIO1,18,15,74,70,8\n"
	"304,305,,TOUCHEXIT,RADIO1,19,15,84,70,8\n"
	"305,306,,TOUCHEXIT,RADIO1,20,15,94,70,8\n"
	"306,307,,, EDVAL1,21,28,62,35,10\n"
	"307,,,LASTOBJ,LTEXT,22,65,62,20,8";

bool
Tick::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Tick"};
	TabSHEET tab2 = {64, 90, 10, "Edit"};
	TabSHEET tab3 = {25, 64, 10, "Direction"};
	double tick_rot;
	void *dyndata[] = {(void*)"Apply to TICK", (void*)"Apply to AXIS",  (void*)&tab1, (void*)&tab2,
		(void*)&tab3, (void*)"tick size", (void*)&size, (void*)"major tick", (void*)"type:",
		(void*)"symmetric", (void*)"draw grid line(s)", (void*)"value:", (void*)&value, (void*)"label:",
		(void*)"direction of ticks", (void*)"perpendicular to axis", (void*)"fixed angle",
		(void*)"x-axis", (void*)"y-axis", (void*)"z-axis", (void*)&tick_rot, (void*)"deg."};
	DlgInfo *TickDlg;
	DlgRoot *Dlg;
	void *hDlg;
	DWORD old_flags;
	char old_value[80];
	double new_size, old_size, new_angle, old_angle, new_value;
	int res, tmp_type = type;
	bool bRet = false;
	DWORD new_flags = flags, undo_flags = 0;
	anyOutput *cdisp = Undo.cdisp;
	char *old_label = 0L;
	TextDEF *td;

	if(!parent || parent->Id != GO_AXIS) return false;
	if(!(TickDlg = CompileDialog(TickDlg_Tmpl, dyndata))) return false;
	switch(type & 0x0f) {
	case 1:		tick_rot = angle;					break;
	default:	tick_rot = trig2deg(lsi, lcsi);		break;
		}
	old_flags = flags;
	Dlg = new DlgRoot(TickDlg, data);
	Dlg->SetCheck(301 + (type & 0x07), 0L, true);
	if(flags & AXIS_ANGULAR) {
		Dlg->SetText(105, "outside");		Dlg->SetText(106, "inside");
		Dlg->ShowItem(303, false);			Dlg->ShowItem(304, false);
		Dlg->ShowItem(305, false);
		}
	else if(flags & AXIS_3D) {
		Dlg->SetText(105, "positive");		Dlg->SetText(106, "negative");
		if(parent->Id == GO_AXIS) {
			//disable tick direction onto the axis
			switch(parent->type) {
			case 1:	Dlg->Activate(303, false);	break;
			case 2:	Dlg->Activate(304, false);	break;
			case 3:	Dlg->Activate(305, false);	break;
				}
			}
		}
	else {
		Dlg->ShowItem(303, false);	Dlg->ShowItem(304, false);
		Dlg->ShowItem(305, false);
		if(abs(pts[1].x - pts[0].x) > abs(pts[1].y - pts[0].y)){
			Dlg->SetText(105, "right");		Dlg->SetText(106, "left");
			}
		else {
			Dlg->SetText(105, "up");		Dlg->SetText(106, "down");
			}
		}
	if(label) {
		if(label->Command(CMD_GETTEXT, &TmpTxt, 0L) && TmpTxt[0] && 
			(old_label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0)))
			Dlg->SetText(203, old_label);
		if(label->Id != GO_LABEL) Dlg->Activate(203, false);
		}
	switch(flags &0x03) {
	case AXIS_NEGTICKS:		Dlg->SetCheck(106, 0L, true);		break;
	case AXIS_SYMTICKS:		Dlg->SetCheck(107, 0L, true);		break;
	default:				Dlg->SetCheck(105, 0L, true);		break;
		}
	if(flags & AXIS_GRIDLINE) Dlg->SetCheck(108, 0L, true); 
	if(!(flags & AXIS_MINORTICK)) Dlg->SetCheck(103, 0L, true);
	if(Dlg->GetValue(101, &old_size)) new_size = old_size;
	else new_size = old_size = size;
	if(Dlg->GetValue(306, &old_angle)) new_angle = old_angle;
	else new_angle = old_angle = tick_rot;
	if(flags & AXIS_DATETIME) Dlg->SetText(201, NiceTime(value));
	if(!(Dlg->GetText(201, old_value, sizeof(old_value)))) {
		new_value = value;	old_value[0] = 0;
		}
	hDlg = CreateDlgWnd("Tick properties", 50, 50, 375, 265, Dlg, 0x4L);
	do {
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 1:		case 2:
			Undo.SetDisp(cdisp);				new_flags &= ~0x7;
			if(Dlg->GetCheck(105)) new_flags |= AXIS_POSTICKS;
			else if(Dlg->GetCheck(106)) new_flags |= AXIS_NEGTICKS;
			else new_flags |= AXIS_SYMTICKS;
			if(Dlg->GetCheck(108)) new_flags |= AXIS_GRIDLINE;
			Dlg->GetValue(101, &new_size);		Dlg->GetValue(306, &new_angle);
			break;
		case 301:	case 302:	case 303:	case 304:	case 305:
			tmp_type = (tmp_type & ~0x0f) | (res -301);
			res = -1;
			break;
			}
		}while (res <0);
	if(res == 1) {
		if(Dlg->GetCheck(103)) new_flags &= ~AXIS_MINORTICK;
		else new_flags |= AXIS_MINORTICK;
		undo_flags = CheckNewDword(&flags, flags, new_flags, parent, undo_flags);
		undo_flags = CheckNewInt(&type, type, tmp_type, parent, undo_flags);
		undo_flags = CheckNewFloat(&size, old_size, new_size, parent, undo_flags);
		undo_flags = CheckNewFloat(&angle, old_angle, new_angle, parent, undo_flags);
		if(Dlg->GetText(201, TmpTxt, 80) && strcmp(TmpTxt, old_value)) {
			Undo.ValFloat(parent, &value, undo_flags);		undo_flags |= UNDO_CONTINUE;
			if(flags & AXIS_DATETIME) date_value(TmpTxt, 0L, &value);
			else Dlg->GetValue(201, &value);
			}
		if(label && label->Id == GO_LABEL) {
			td = ((Label*)label)->GetTextDef();
			if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
			if(undo_flags = CheckNewString(&td->text, td->text, TmpTxt, this, undo_flags))
				label->Command(CMD_SETTEXT, TmpTxt, 0L);
			}
		if (undo_flags & UNDO_CONTINUE) bRet = true;
		}
	else if(res == 2) {
		parent->Command(CMD_SAVE_TICKS, 0L, 0L);
		if((new_flags & 0x07) != (old_flags & 0x07)) 
			parent->Command(CMD_SET_TICKSTYLE, &new_flags, 0L);
		parent->SetSize(SIZE_AXIS_TICKS, new_size);
		parent->Command(CMD_TICK_TYPE, &tmp_type, 0L);
		parent->SetSize(SIZE_TICK_ANGLE, new_angle);
		parent->Command(CMD_REDRAW, 0L, 0L);
		bRet = true;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(TickDlg);
	if(old_label) free(old_label);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Axis properties dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *ssTickTmpl =
	"1,2,,DEFAULT, PUSHBUTTON,-1,113,10,45,12\n"
	"2,3,,, PUSHBUTTON,-2,113,25,45,12\n"
	"3,4,,, LTEXT,1,5,10,100,9\n"
	"4,5,,TOUCHEXIT,RANGEINPUT,4,10,20,90,10\n"
	"5,6,,, LTEXT,2,5, 32, 100, 9\n"
	"6,7,,TOUCHEXIT,RANGEINPUT,5,10,42,90,10\n"
	"7, 8,,,LTEXT,3, 5, 54, 80, 8\n"
	"8,,,LASTOBJ | TOUCHEXIT,RANGEINPUT,6,10,64,90,10";

bool
Axis::ssTicks()
{
	void *dyndata[] ={(void*)"range for major tick VALUES:", (void*)"range for major tick LABELS:",
		(void*)"minor tick VALUES:", (void*)ssMATval, (void*)ssMATlbl, (void*)ssMITval};
	DlgInfo *TickDlg = CompileDialog(ssTickTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int res, n, n1, n2, n3;
	bool bRet = false, bContinue = true;
	AccRange *rT, *rL, *rMT;

	if(!data) return false;
	n = n1 = n2 = n3 = 0;			rT = rL = rMT = 0L;
	if(!(Dlg = new DlgRoot(TickDlg, data)))return false;
	hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x4L);
	Dlg->Activate(4, true);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res) {
		case 0:								// focus lost
			if(bContinue) res = -1;
			break;
		case 4:		case 6:		case 8:
			bContinue = true;
			res = -1;			break;
		case 1:
			if(rT) delete rT;		if(rL) delete rL;		if(rMT) delete rMT;
			n = n1 = n2 = n3 = 0;	rT = rL = rMT = 0L;
			if(Dlg->GetText(4,TmpTxt, TMP_TXT_SIZE) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
				if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE) && (rL = new AccRange(TmpTxt)) && 
					(n2 = rL->CountItems()) && n1 != n2){
					ErrorBox("Ranges for tick values\nand tick labels must"
						" have\nthe same size");
					res = -1;		bContinue = true;
					break;
					}
				}
			if(Dlg->GetText(8,TmpTxt,TMP_TXT_SIZE) && (rMT=new AccRange(TmpTxt)) && (n3=rMT->CountItems())){
				//minor ticks are valid
				}
			if(!(n = n1 + n3)) {
				ErrorBox("Ranges not valid or\nno range specified");
				res = -1;			bContinue = true;
				}
			}
		}while (res < 0);
	if(res == 1 && n) {
		if(n1) {
			if(ssMATval) free(ssMATval);	if(ssMATlbl) free(ssMATlbl);
			if(ssMITval) free(ssMITval);	ssMATval = ssMATlbl = ssMITval = 0L;
			if(Dlg->GetText(4, TmpTxt, TMP_TXT_SIZE)) 
				ssMATval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
			if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE))
				ssMATlbl = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
			if(Dlg->GetText(8, TmpTxt, TMP_TXT_SIZE))
				ssMITval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
			UpdateTicks();
			}
		bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;			free(TickDlg);
	if(rT) delete rT;	if(rL) delete rL;	if(rMT) delete rMT;
	return bRet;
}

static char *AxisPropDlg_Tmpl =
	"1,2,,DEFAULT,PUSHBUTTON,-1,186,10,45,12\n"
	"2,3,,,PUSHBUTTON,-2,186,25,45,12\n"
	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
	"4,5,50,ISPARENT | CHECKED,SHEET,1,5,10,168,165\n"
	"5,6,200,ISPARENT,SHEET,2,5,10,168,165\n"
	"6,7,300,ISPARENT,SHEET,3,5,10,168,165\n"
	"7,8,400,ISPARENT,SHEET,4,5,10,168,165\n"
	"8,9,500,HIDDEN | ISPARENT,SHEET,5,5,10,168,165\n"
	"9,,550,HIDDEN | ISPARENT,SHEET,6,5,10,168,165\n"
	"50,+,100,ISPARENT | CHECKED,GROUPBOX,7,10,30,158,36\n"
	".,104,,TOUCHEXIT,CHECKBOX,8,17,37,80,8\n"
	"100,+,,,RTEXT,9,10,51,35,8\n"
	".,.,,,EDVAL1,10,48,51,51,10\n"
	".,.,,,CTEXT,11,100,51,11,8\n"
	".,,,,EDVAL1,12,112,51,51,10\n"
	".,120,105,ISPARENT | CHECKED,GROUPBOX,13,10,72,158,45\n"
	".,106,,TOUCHEXIT | ISRADIO,CHECKBOX,-20,54,77,20,8\n"
	".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-21,84,77,20,8\n"
	".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-22,54,77,20,8\n"
	".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-23,84,77,20,8\n"
	".,.,,,RTEXT,-4,10,-50,15,8\n"
	".,.,,,EDVAL1,14,27,-50,45,10\n"
	".,.,,,LTEXT,-7,75,-50,5,8\n"
	".,.,,,EDVAL1,15,81,-50,45,10\n"
	".,.,,,LTEXT,0,129,-50,15,8\n"
	".,.,,,RTEXT,-5,10,-38,15,8\n"
	".,.,,,EDVAL1,16,27,-38,45,10\n"
	".,.,,,LTEXT,-7,75,-38,5,8\n"
	".,.,,,EDVAL1,17,81,-38,45,10\n"
	".,150,,,LTEXT,0,129,-38,15,8\n"
	"150,+,,,RTEXT,-6,10,-26,15,8\n"
	".,.,,,EDVAL1,18,27,-26,45,10\n"
	".,.,,,LTEXT,-7,75,-26,5,8\n"
	".,.,,,EDVAL1,19,81,-26,45,10\n"
	".,,,,LTEXT,0,129,-26,15,8\n"
	"120,180, 121, ISPARENT | CHECKED,GROUPBOX,20,10,123,158,20\n"
	".,+,,,RTEXT,21,20,128,25,8\n"
	".,.,,,EDVAL1,22,47,128,25,10\n"
	".,.,,,LTEXT,-3,73,128, 10,8\n"
	".,.,,,RTEXT,-11,102,128,25,8\n"
	".,130,,OWNDIALOG, COLBUTT,23,129,128,25,10\n"
	"130,,131,ISPARENT | CHECKED,GROUPBOX,24,10,149,158,20\n"
	"131,,,,EDTEXT,0,15,154,148,10\n"
	"180,,181,HIDDEN | ISPARENT | CHECKED,GROUPBOX,25,10,72,158,45\n"
	"181,+,,,RTEXT,26,10,-38,50,8\n"
	".,.,,,EDVAL1,27,62,-38,45,10\n"
	".,.,,,LTEXT,-3,109,-38,15,8\n"
	".,.,,,RTEXT,-5,10,-50,50,8\n"
	".,.,,,EDVAL1,28,62,-50,45,10\n"
	".,.,,,LTEXT,-3,109,-50,15,8\n"
	".,.,,,RTEXT,29,10,-38,50,8\n"
	".,.,,,EDVAL1,30,62,-38,45,10\n"
	".,.,,,LTEXT,-3,109,-38,15,8\n"
	"200,+,,TOUCHEXIT,RADIO1,31,20,35,40,8\n"
	".,.,,TOUCHEXIT,RADIO1,32,20,47,40,8\n"
	".,204,,TOUCHEXIT,RADIO1,33,20,59,40,8\n"
	".,.,,TOUCHEXIT,RADIO1,34,20,71,40,8\n"
	".,203,250,CHECKED | ISPARENT,GROUPBOX,35,15,75,148,50\n"
	".,206,,,PUSHBUTTON,36,30,130,90,12\n"
	".,,,TOUCHEXIT,RADIO1,0,20,130,8,8\n"
	"250,+,,,RTEXT,37,35,83,45,8\n"
	".,.,,,EDVAL1,38,87,83,65,10\n"
	".,.,,,RTEXT,39,35,95,45,8\n"
	".,.,,,EDVAL1,40,87,95,65,10\n"
	".,.,,,RTEXT,41,25,107,75,8\n"
	".,,,,EDTEXT,42,107,107,45,10\n"
	"300,+,,,LTEXT,43,20,30,110,8\n"
	".,.,,TOUCHEXIT,RADIO1,44,40,45,70,8\n"
	".,.,,TOUCHEXIT,RADIO1,45,40,57,70,8\n"
	".,.,,TOUCHEXIT,RADIO1,46,40,69,70,8\n"
	".,.,,TOUCHEXIT,RADIO1,47,40,81,70,8\n"
	".,,,,CHECKBOX,48,20,115,80,12\n"
	"400,450,,,LTEXT,-27,10,30,110,8\n"
	".,402,,ISRADIO,ODBUTTON,49,49,40,25,25\n"
	".,.,,ISRADIO,ODBUTTON,49,74,40,25,25\n"
	".,.,,ISRADIO,ODBUTTON,49,99,40,25,25\n"
	".,.,,ISRADIO,ODBUTTON,49,124,40,25,25\n"
	".,.,,,RTEXT,50,25,75,48,8\n"
	".,.,,,EDVAL1,51,75,75,29,10\n"
	".,.,,,LTEXT,-3,107,75,10,8\n"
	".,.,,,RTEXT,52,25,87,48,8\n"
	".,.,,,EDVAL1,53,75,87,29,10\n"
	".,,,,LTEXT,-3,107,87,10,8\n"
	"450,+,,ISPARENT | CHECKED,GROUPBOX,54,10,110,158,50\n"
	".,.,,,LTEXT,0,30,115,60,8\n"
	".,.,,,PUSHBUTTON,-8,108,142,41,12\n"
	".,.,,,PUSHBUTTON,-9,67,142,41,12\n"
	".,.,,,RTEXT,55,25,125,20,8\n"
	".,.,,,EDTEXT,0,47,125,41,10\n"
	".,.,,,RTEXT,56,92,125,9,8\n"
	".,.,,,EDTEXT,0,103,125,41,10\n"
	".,401,,,PUSHBUTTON,57,26,142,41,12\n"
	"500,,,NOSELECT,ODBUTTON,58,25,30,140,140\n"
	"550,,551,ISPARENT | CHECKED,GROUPBOX,59,15,30,148,123\n"
	".,+,,TOUCHEXIT,RADIO1,60,30,38,75,9\n"
	".,.,,ODEXIT,COLBUTT,61,112,37,25,10\n"
	".,.,,TOUCHEXIT,RADIO1,62,30,52,80,9\n"
	".,.,,TOUCHEXIT,RADIO1,63,30,76,80,9\n"
	".,.,,TOUCHEXIT,RADIO1,64,30,88,80,9\n"
	".,.,,TOUCHEXIT,RADIO1,65,30,64,80,9\n"
	".,.,,OWNDIALOG | TOUCHEXIT,COLBUTT,66,50,100,25,10\n"
	".,.,,,CTEXT,56,76,100,18,9\n"
	".,.,,ODEXIT,COLBUTT,67,95,100,25,10\n"
	".,.,,,CHECKBOX,68,30,115,80,9\n"
	".,.,,,RTEXT,69,30,128,45,9\n"
	".,.,,,INCDECVAL1,70,77,128,32,10\n"
	".,,,LASTOBJ,LTEXT,-10,111,128,10,9";

bool
Axis::PropertyDlg()
{
	TabSHEET tab1 = {0, 25, 10, "Axis"};
	TabSHEET tab2 = {25, 50, 10, "Ticks"};
	TabSHEET tab3 = {50, 97, 10, "Transforms"};
	TabSHEET tab4 = {97, 128, 10, "Breaks"};
	TabSHEET tab5 = {128, 153, 10, "Plots"};
	TabSHEET tab6 = {97, 135, 10, "Gradient"};
	int v1 = (axis->flags & AXIS_3D) ? 77 : (axis->flags & AXIS_RADIAL) ? 83 : 89; 
	double transp = (double)iround((double)((gTrans>>24) & 0xff)/2.55);
	void *dyndata[] ={(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)&tab4, (void*)&tab5, (void*)&tab6,
		(void*)" scaling ", (void*)" automatic scaling", (void*)"axis from", (void*)&axis->min, (void*)"to",
		(void*)&axis->max, (void*)" placement ", (void*)&axis->loc[0].fx, (void*)&axis->loc[1].fx,
		(void*)&axis->loc[0].fy, (void*)&axis->loc[1].fy, (void*)&axis->loc[0].fz, (void*)&axis->loc[1].fz,
		(void*)" line ", (void*)"width", (void*)&sizAxLine, (void*)&colAxis, (void*)" axis label ",
		(void*)" placement ", (void*)"center x", (void*)&axis->Center.fx, (void*)&axis->Center.fy,
		(void*)"radius", (void*)&axis->Radius, (void*)"no ticks", (void*)"automatic", (void*)"leave unchanged",
		(void*)"set manually", (void*)"                            ", (void*)"use spread sheet values",
		(void*)"start value", (void*)&axis->Start, (void*)"interval", (void*)&axis->Step,
		(void*)"minor ticks per interval", (void*)"0", (void*)"Transforms:",  (void*)"none (linear)",
		(void*)"logarithmic (log base 10)", (void*)"reciprocal (1/x)",(void*)"square root",
		(axis->loc[0].fx == axis->loc[1].fx) ? (void*)"low vaues top of graph" : (void*)"low values right of graph",
		(void*)(OD_BreakTempl), (void*)"break gap", (void*)&brkgap, (void*)"symbol size",  (void*)&brksymsize,
		(void*)" break data ", (void*)"from", (void*)"to", (void*)"Delete", (void*)OD_axisplot,
		(void*)" color gradient ", (void*)"use common fill color:", (void *)&gCol_0,
		(void*)"rainbow color gradient I", (void*)"extented rainbow colors", (void*)"simple color gradient",
		(void*)"rainbow color gradient II", (void *)&gCol_1, (void *)&gCol_2, (void*)"invert gradient",
		(void*)"transparency", (void*)&transp};
	DlgInfo *AxisPropDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, res, nbrk, cbrk, ttmpl, n_gradient;
	double tmp, tmp2, old_x1, old_x2, old_y1, old_y2;
	bool bRet = false, bChanged = false, upd_brk = true;
	bool bContinue = false, bUpdPG = false;
	double use_step = 10.0, use_minmax[] = {0.0, 100.0};
	DWORD new_color, undo_flags = 0L;
	anyOutput *cdisp = Undo.cdisp;
	lfPOINT *brks = 0L, *tmpbrks = 0L;
	char *old_Label = 0L, *type_txt;
	TextDEF label_def, *lb_def;
	char **names;
	GraphObj **somePlots = 0L, **scp = 0L;
	AxisDEF old_a, new_a;
	void *sv_ptr;

	nbrk = cbrk = 0;
	if(!parent) return false;
	if(!(AxisPropDlg = CompileDialog(AxisPropDlg_Tmpl, dyndata))) return false;
	n_gradient = grad_type;
	//adjust dialog to 3D plot, polar plot ...
	for(i = 0, v1+= 50; !(AxisPropDlg[i].flags & LASTOBJ); i++) {
		if(AxisPropDlg[i].y < 0) AxisPropDlg[i].y += v1;
		}
	if(parent->Id == GO_GRAPH && (res=((Graph*)parent)->nscp)){
		scp = ((Graph*)parent)->Sc_Plots;
		CurrAxes = ((Graph*)parent)->Axes;
		if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
			!(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
			return false;
		if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
		for(i = 0, j = 1; i < res; i++) {
			if(scp[i] && scp[i]->name){
				names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
				somePlots[j++] = scp[i];
				}
			}
		}
	else if(IsPlot3D(parent) && (res=((Plot3D*)parent)->nscp)){
		scp = ((Plot3D*)parent)->Sc_Plots;
		CurrAxes = ((Plot3D*)parent)->Axes;
		if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
			!(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
			return false;
		if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
		for(i = 0, j = 1; i < res; i++) {
			if(scp[i] && scp[i]->name){
				names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
				somePlots[j++] = scp[i];
				}
			}
		}
	else {
		names = (char**)calloc(2, sizeof(char*));	names[0] = (char*)malloc(10*sizeof(char));
		rlp_strcpy(names[0], 10, "n.a.");
		}
	OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
	if(!(Dlg = new DlgRoot(AxisPropDlg, data)))return false;
	if(names && somePlots) Dlg->ShowItem(8, true);		//show tab
	if(axis->breaks && axis->nBreaks) {
		if(!(brks = (lfPOINT*)calloc(axis->nBreaks+2, sizeof(lfPOINT)))) return false;
		memcpy(brks, axis->breaks, axis->nBreaks*sizeof(lfPOINT));
		nbrk = axis->nBreaks-1;
		WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
		Dlg->SetText(455, TmpTxt+1);
		WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
		Dlg->SetText(457, TmpTxt+1);
		}
	switch(brksym) {
	case 2:		Dlg->SetCheck(402, 0L, true);	break;
	case 3:		Dlg->SetCheck(403, 0L, true);	break;
	case 4:		Dlg->SetCheck(404, 0L, true);	break;
	default:	Dlg->SetCheck(401, 0L, true);	break;
		}
	if(!(axis->flags & 0x03)) Dlg->SetCheck(ttmpl = 200, 0L, true);
	else if(axis->flags & AXIS_AUTOTICK)Dlg->SetCheck(ttmpl = 201, 0L, true);
	else if(Ticks) Dlg->SetCheck(ttmpl = 202, 0L, true);
	else Dlg->SetCheck(ttmpl = 201, 0L, true);
	Dlg->Activate(251, false);	Dlg->Activate(253, false);	Dlg->Activate(255, false);
	Dlg->SetCheck(305, 0L, (AXIS_INVERT == (axis->flags & AXIS_INVERT)));
	if(axis->flags & AXIS_AUTOSCALE) {
		Dlg->SetCheck(51, 0L, true);
		Dlg->Activate(101, false);		Dlg->Activate(103, false);
		}
	//check transforms
	switch(axis->flags & 0x7000L) {
	case AXIS_LINEAR:	Dlg->SetCheck(301, 0L, true);	break;
	case AXIS_LOG:		Dlg->SetCheck(302, 0L, true);	break;
	case AXIS_RECI:		Dlg->SetCheck(303, 0L, true);	break;
	case AXIS_SQR:		Dlg->SetCheck(304, 0L, true);	break;
		}
	if(axis->flags & AXIS_3D) {
		Dlg->ShowItem(105, false);	Dlg->ShowItem(106, false);
		Dlg->ShowItem(107, false);	Dlg->ShowItem(108, false);
		}
	else if(axis->flags & AXIS_ANGULAR) {
		Dlg->ShowItem(104, false);	Dlg->ShowItem(130, false);
		Dlg->ShowItem(180, true);	Dlg->ShowItem(7, false);
		}
	else {
		if(axis->flags & AXIS_RADIAL) {
			Dlg->ShowItem(105, false);	Dlg->ShowItem(106, false);
			Dlg->ShowItem(107, false);	Dlg->ShowItem(108, false);
			}
		Dlg->ShowItem(150, false);	Dlg->ShowItem(151, false);
		Dlg->ShowItem(152, false);	Dlg->ShowItem(153, false);
		Dlg->ShowItem(154, false);
		if(axis->loc[0].fx != axis->loc[1].fx) {
			Dlg->ShowItem(105, false);	Dlg->ShowItem(106, false);
			}
		if(axis->loc[0].fy != axis->loc[1].fy) {
			Dlg->ShowItem(107, false);	Dlg->ShowItem(108, false);
			}
		}
	//align to frame ?
	switch(axis->flags & 0x70) {
		case AXIS_LEFT: Dlg->SetCheck(105, 0L, true);	break;
		case AXIS_RIGHT: Dlg->SetCheck(106, 0L, true);	break;
		case AXIS_TOP: Dlg->SetCheck(107, 0L, true);	break;
		case AXIS_BOTTOM: Dlg->SetCheck(108, 0L, true);	break;
		}
	if(axis->flags & AXIS_X_DATA) Dlg->SetText(113, "[data]");
	else Dlg->SetText(113, Units[defs.cUnits].display);
	if(axis->flags & AXIS_Y_DATA) Dlg->SetText(118, "[data]");
	else Dlg->SetText(118, Units[defs.cUnits].display);
	if(axis->flags & AXIS_Z_DATA) Dlg->SetText(118, "[data]");
	else Dlg->SetText(154, Units[defs.cUnits].display);
	//any label ?
	if(axisLabel){
		TmpTxt[0] = 0;
		axisLabel->Command(CMD_GETTEXT, TmpTxt, 0L);
		Dlg->SetText(131,TmpTxt);
		old_Label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
		if(axisLabel->Id == GO_MLABEL) Dlg->Activate(131, false);
		}
	else Dlg->SetText(131, 0L);
	//remember: any updated values ?
	Dlg->GetValue(110, &old_x1);		Dlg->GetValue(112, &old_x2);
	Dlg->GetValue(115, &old_y1);		Dlg->GetValue(117, &old_y2);
	switch(type) {
	case 1:		type_txt = (char*)(&"X-a");		break;
	case 2:		type_txt = (char*)(&"Y-a");		break;
	case 3:		type_txt = (char*)(&"Z-a");		break;
	case 4:		type_txt = (char*)(&"Gradient A");	break;
	default:	type_txt = (char*)(&"A");		break;
		}
	//angular radial axis specials
	if(axis->flags & AXIS_ANGULAR){
		Dlg->SetText(305, "set direction cw");
		type_txt = (char*)(&"angular a");
		}
	if(axis->flags & AXIS_RADIAL) type_txt = (char*)(&"radial a");
	//save old axis definition
	memcpy(&old_a, axis, sizeof(AxisDEF));
	Dlg->GetValue(101, &old_a.min);		Dlg->GetValue(103, &old_a.max);
	Dlg->GetValue(110, &old_a.loc[0].fx);	Dlg->GetValue(112, &old_a.loc[1].fx);
	Dlg->GetValue(115, &old_a.loc[0].fy);	Dlg->GetValue(117, &old_a.loc[1].fy);
	Dlg->GetValue(151, &old_a.loc[0].fz);	Dlg->GetValue(153, &old_a.loc[1].fz);
	Dlg->GetValue(182, &old_a.Center.fx);	Dlg->GetValue(185, &old_a.Center.fy);
	Dlg->GetValue(188, &old_a.Radius);
	memcpy(&new_a, &old_a, sizeof(AxisDEF));
	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, type_txt);
	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "xis Properties");
	if((type &0x0f) == 4) {
		Dlg->ShowItem(7, false);	Dlg->ShowItem(8, false);
		Dlg->ShowItem(9, true);		upd_brk = false;
		switch(grad_type & 0x0f) {
		case 0:
			Dlg->SetCheck(551, 0L, true);				break;
		case 1:		default:
			grad_type = n_gradient = 1;
			Dlg->SetCheck(553, 0L, true);				break;
		case 2:		case 3:		case 4:
			Dlg->SetCheck(552+(grad_type & 0x0f), 0L, true);	break;
			}
		if(grad_type & 0x10) Dlg->SetCheck(560, 0L, true);
		Dlg->ItemCmd(562, CMD_STEP, (void*)&use_step);
		Dlg->ItemCmd(562, CMD_MINMAX, (void*)&use_minmax);
		}
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 476, 390, Dlg, 0x4L);
	switch(axis->flags & 0x70) {
		case AXIS_LEFT: 
		case AXIS_RIGHT:
			Dlg->Activate(110, false);			Dlg->Activate(112, false);
			break;
		case AXIS_TOP:
		case AXIS_BOTTOM:
			Dlg->Activate(115, false);			Dlg->Activate(117, false);
			break;
			}
	do{
		if(upd_brk) {
			Dlg->ShowItem(453, cbrk > 0);
#ifdef USE_WIN_SECURE
			sprintf_s(TmpTxt, TMP_TXT_SIZE, "break # %d/%d", cbrk+1, nbrk+1);
#else
			sprintf(TmpTxt,"break # %d/%d", cbrk+1, nbrk+1);
#endif
			Dlg->SetText(451, TmpTxt);
			upd_brk = false;
			}
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:							//lost focus ?
			if(bContinue) res = -1;
			ShowDlgWnd(hDlg);
			break;
		case -1:
			bContinue = false;
			break;
		case 51:
			if(Dlg->GetCheck(51)) {
				Dlg->Activate(101, false);		Dlg->Activate(103, false);
				}
			else {
				Dlg->Activate(101, true);		Dlg->Activate(103, true);
				}
			res = -1;
			break;
		case 105:	case 106:	case 107:	case 108:		//axis left | right | top | bottom
			if(Dlg->GetCheck(105) || Dlg->GetCheck(106)) {
				Dlg->Activate(110, false);			Dlg->Activate(112, false);
				}
			else {
				Dlg->Activate(110, true);			Dlg->Activate(112, true);
				}
			if(Dlg->GetCheck(107) || Dlg->GetCheck(108)) {
				Dlg->Activate(115, false);			Dlg->Activate(117, false);
				}
			else {
				Dlg->Activate(115, true);			Dlg->Activate(117, true);
				}
			res = -1;
			break;
		case 301:	case 302:	case 303:	case 304:		//transform radiobuttons
			new_a.flags &= ~0x7000L;
			if(res == 302) new_a.flags |= AXIS_LOG;
			else if(res == 303) new_a.flags |= AXIS_RECI;
			else if(res == 304) new_a.flags |= AXIS_SQR;
			res = -1;
			break;
		case 200:	case 201:	case 202:
			ttmpl = res;
			Dlg->Activate(251, false);	Dlg->Activate(253, false);	Dlg->Activate(255, false);
			res = -1;
			break;
		case 203:
			ttmpl = res;
			Dlg->Activate(251, true);	Dlg->Activate(253, true);	Dlg->Activate(255, true);
			res = -1;
			break;
		case 205:	case 206:
			Dlg->SetCheck(206, 0L, true);
			if (ssTicks()) {
				Dlg->SetCheck(ttmpl = 202, 0L, true);	Dlg->Activate(251, false);
				Dlg->Activate(253, false);	Dlg->Activate(255, false);
				undo_flags |= UNDO_CONTINUE;	res = 1;
				}
			else {
				Dlg->SetCheck(ttmpl, 0L, true);
				res = -1;
				}
			bContinue = true;
			break;
		case 452:			//next break
			if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
				if(!brks && (brks = (lfPOINT*)calloc(2, sizeof(lfPOINT)))) {
					brks[0].fx = tmp;		brks[0].fy = tmp2;
					cbrk = nbrk = 0;
					}
				if(!brks) return false;		//mem allocation error
				if(cbrk && cbrk >= nbrk) {
					if(tmpbrks = (lfPOINT*)realloc(brks, (cbrk+2)*sizeof(lfPOINT))){
						brks = tmpbrks;
						brks[cbrk].fx = tmp;		brks[cbrk].fy = tmp2;
						brks[cbrk+1].fx = brks[cbrk+1].fy = 0.0;
						}
					else return false;		//mem allocation error
					}
				else {
					brks[cbrk].fx = tmp;		brks[cbrk].fy = tmp2;
					}
				cbrk++;
				}
			if(cbrk>nbrk){
				nbrk = cbrk;
				Dlg->SetText(455,0L);		Dlg->SetText(457,0L);
				}
			else if(nbrk){
				if(brks[cbrk].fx == brks[cbrk].fy && cbrk == nbrk) {
					Dlg->SetText(455,0L);		Dlg->SetText(457,0L);
					}
				else {
					WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
					Dlg->SetText(455, TmpTxt+1);
					WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
					Dlg->SetText(457, TmpTxt+1);
					}
				}
			bChanged = upd_brk = true;
			res= -1;
			break;
		case 453:			//previous break
			if(cbrk >0){
				if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
					brks[cbrk].fx = tmp;		brks[cbrk].fy = tmp2;
					}
				else if(cbrk == nbrk)nbrk--;
				cbrk--;
				WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
				Dlg->SetText(455, TmpTxt+1);
				WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
				Dlg->SetText(457, TmpTxt+1);
				}
			bChanged = upd_brk = true;
			res= -1;
			break;
		case 458:			//delete break;
			if(brks && nbrk > cbrk) {
				for(i = cbrk; i < nbrk; i++) {
					brks[i].fx = brks[i+1].fx;
					brks[i].fy = brks[i+1].fy;
					}
				nbrk--;
				if(brks[cbrk].fx == brks[cbrk].fy && cbrk == nbrk) {
					Dlg->SetText(455,0L);		Dlg->SetText(457,0L);
					}
				else {
					WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
					Dlg->SetText(455, TmpTxt+1);
					WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
					Dlg->SetText(457, TmpTxt+1);
					}
				}
			else {
				Dlg->SetText(455,0L);		Dlg->SetText(457,0L);
				}
			bChanged = upd_brk = true;
			res = -1;
			break;
		case 551:
			n_gradient = 0;
			res = -1;		break;
		case 552:					//gradient color button 0
			Dlg->SetCheck(551, 0L, true);	n_gradient = 0;		res = -1;
			break;
		case 553:	case 554:	case 555:	case 556:
			n_gradient = (res-552);
			res = -1;		break;
		case 557:	case 559:			//gradient color button 1 and 2
			Dlg->SetCheck(555, 0L, true);	n_gradient = 3;		res = -1;
			break;
			}
		}while (res < 0);
	Undo.SetDisp(cdisp);
	switch (res) {
	case 1:									//OK pressed
		bModified = true;
		if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
			if(!brks && (brks = (lfPOINT*)calloc(2, sizeof(lfPOINT)))) {
				brks[0].fx = tmp;	brks[0].fy = tmp2;	cbrk = nbrk = 1;
				}
			else if(brks) {
				brks[cbrk].fx = tmp;	brks[cbrk].fy = tmp2;	nbrk++;
				}
			}
		Dlg->GetValue(101, &new_a.min);		Dlg->GetValue(103, &new_a.max);
		Dlg->GetValue(110, &new_a.loc[0].fx);	Dlg->GetValue(112, &new_a.loc[1].fx);
		Dlg->GetValue(115, &new_a.loc[0].fy);	Dlg->GetValue(117, &new_a.loc[1].fy);
		Dlg->GetValue(151, &new_a.loc[0].fz);	Dlg->GetValue(153, &new_a.loc[1].fz);
		Dlg->GetValue(182, &new_a.Center.fx);	Dlg->GetValue(185, &new_a.Center.fy);
		Dlg->GetValue(188, &new_a.Radius);
		new_a.breaks = brks;					new_a.nBreaks = nbrk;
		if(new_a.breaks) SortAxisBreaks(&new_a);
		brks = 0L;	nbrk = 0;
		if(Dlg->GetCheck(51)) {
			if(!(new_a.flags & AXIS_AUTOSCALE)) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			new_a.flags |= AXIS_AUTOSCALE;
			}
		else new_a.flags &= ~AXIS_AUTOSCALE;
		if(Dlg->GetCheck(201)) new_a.flags |= AXIS_AUTOTICK;
		else new_a.flags &= ~AXIS_AUTOTICK;
		if(Dlg->GetCheck(200)) new_a.flags &= ~0x03;
		if(Dlg->GetCheck(305)) new_a.flags |= AXIS_INVERT;
		else new_a.flags &= ~AXIS_INVERT;
		new_a.flags &= ~0x70;
		if(Dlg->GetCheck(105)) new_a.flags |= AXIS_LEFT;
		else if(Dlg->GetCheck(106)) new_a.flags |= AXIS_RIGHT;
		else if(Dlg->GetCheck(107)) new_a.flags |= AXIS_TOP;
		else if(Dlg->GetCheck(108)) new_a.flags |= AXIS_BOTTOM;
		if((new_a.flags & AXIS_LOG)== AXIS_LOG && new_a.min < defs.min4log) {
			switch(type & 0x0f) {
			case 1:
				new_a.min = parent->GetSize(SIZE_BOUNDS_XMIN);	break;
			case 2:
				new_a.min = parent->GetSize(SIZE_BOUNDS_YMIN);	break;
			case 3:
				new_a.min = parent->GetSize(SIZE_BOUNDS_ZMIN);	break;
				}
			}
		if(cmpAxisDEF(&old_a, &new_a)) {
			bChanged = true;
			if(axis->flags != new_a.flags) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
			Undo.AxisDef(this, axis, undo_flags);
			memcpy(axis, &new_a, sizeof(AxisDEF));	undo_flags |= UNDO_CONTINUE;
			axis->Start = axis->min;
			}
		else if(new_a.breaks) free(new_a.breaks);
		if(axis->nBreaks && Dlg->GetValue(406, &tmp))
			undo_flags = CheckNewFloat(&brkgap, brkgap, tmp, this, undo_flags);
		if(axis->nBreaks && Dlg->GetValue(409, &tmp))
			undo_flags = CheckNewFloat(&brksymsize, brksymsize, tmp, this, undo_flags);
		if(Dlg->GetCheck(402)) i = 2;
		else if(Dlg->GetCheck(403)) i = 3;
		else if(Dlg->GetCheck(404)) i = 4;
		else i = 0;
		if(axis->nBreaks) undo_flags = CheckNewInt(&brksym, brksym, i, this, undo_flags);
		if((!(axis->flags & 0x03) && Ticks && NumTicks)	|| (Dlg->GetCheck(203)) ||
			((old_a.flags & 0x7000) != (new_a.flags & 0x7000) && (new_a.flags & AXIS_AUTOTICK))
			|| ((new_a.flags & AXIS_AUTOTICK) &&(new_a.min != old_a.min || new_a.max != old_a.max))){
			Undo.DropListGO(this, (GraphObj ***)&Ticks, &NumTicks, undo_flags);
			undo_flags |= UNDO_CONTINUE;
			}
		if(Dlg->GetCheck(203)) {			//set ticks manually
			if(!Dlg->GetValue(255, &tmp)) tmp = 0.0;
			i = (int)tmp;
			if(!Dlg->GetValue(251, &tmp)) tmp = axis->Start;
			if(!Dlg->GetValue(253, &tmp2)) tmp2 = axis->Step;
			if(!(axis->flags & 0x03)){
				if(axis->flags & AXIS_ANGULAR) axis->flags |= AXIS_POSTICKS;
				else axis->flags |= AXIS_SYMTICKS;
				}
			axis->flags &= ~AXIS_AUTOTICK;
			ManuTicks(tmp, tmp2, i, axis->flags);
			}
		if(!(new_a.flags & 0x03) && (new_a.flags & AXIS_AUTOTICK)){
			if(new_a.flags & AXIS_ANGULAR) axis->flags |= AXIS_POSTICKS;
			else axis->flags |= AXIS_SYMTICKS;
			}
		if(undo_flags & UNDO_CONTINUE) {
			if((axis->flags & AXIS_RADIAL)||(axis->flags & AXIS_ANGULAR))
				parent->Command(CMD_AXIS, this, 0L);
			if(parent->Id == GO_CONTOUR) parent->Command(CMD_RECALC, 0L, 0L);
			}
		if(names && CurrAxes && somePlots) {			//apply axis to plot ?
			for(i = 0; CurrAxes[i] != this; i++);		//find index 
			OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
			if(somePlots[res] && somePlots[res]->Command(CMD_USEAXIS, &i, 0L))
				undo_flags |= UNDO_CONTINUE;
			}
		if(Dlg->GetColor(125, &new_color) && new_color != colAxis) {
			undo_flags = CheckNewDword(&colAxis, colAxis, new_color, this, undo_flags);
			if ((axis->flags & AXIS_ANGULAR) || (axis->flags & AXIS_RADIAL)) {
				Undo.ValDword(this, &GridLine.color, undo_flags);
				GridLine.color = new_color;
				}
			if(Ticks || axisLabel) {
				SavVarInit(200 * NumTicks);
				if(axisLabel){
					axisLabel->FileIO(SAVE_VARS);
					axisLabel->SetColor(COL_TEXT, colAxis);
					}
				if(Ticks) for(i = 0; i < NumTicks; i++)  if(Ticks[i]){
					Ticks[i]->FileIO(SAVE_VARS);
					Ticks[i]->SetColor(COL_AXIS, colAxis);
					}
				sv_ptr = SavVarFetch();
				Undo.SavVarBlock(this, &sv_ptr, undo_flags);
				}
			}
		if(Dlg->GetValue(122, &tmp)) 
			undo_flags = CheckNewFloat(&sizAxLine, sizAxLine, tmp, this, undo_flags);
		if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
			if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
				lb_def = ((Label*)axisLabel)->GetTextDef();
				undo_flags = CheckNewString(&lb_def->text, old_Label, TmpTxt, this, undo_flags);
				}
			else if(!axisLabel) {
				label_def.ColTxt = colAxis;				label_def.ColBg = 0x00ffffffL;
				label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2;
				label_def.RotBL = fabs(si)>0.80 ? 90.0 : 0.0;
				label_def.RotCHAR = 0.0f;				label_def.iSize = 0;
				label_def.Align = TXA_VCENTER | TXA_HCENTER;
				label_def.Mode = TXM_TRANSPARENT;		label_def.Style = TXS_NORMAL;
				label_def.Font = FONT_HELVETICA;		label_def.text = TmpTxt;
				Undo.SetGO(this, &axisLabel, new Label(this, data, 0, 0, &label_def,
					LB_Y_PARENT | LB_X_PARENT), undo_flags);
				undo_flags |= UNDO_CONTINUE;
				}
			}
		else if(axisLabel) {
			Undo.DeleteGO(&axisLabel, undo_flags, 0L);	undo_flags |= UNDO_CONTINUE;
			}
		if((type & 0x0f) == 4) {
			if(Dlg->GetColor(552, &new_color) && gCol_0 != new_color){
				Undo.ValDword(this, &gCol_0, undo_flags);
				gCol_0 = new_color;
				undo_flags |= UNDO_CONTINUE;	bUpdPG = true;
				}
			if(Dlg->GetColor(557, &new_color) && gCol_1 != new_color){
				Undo.ValDword(this, &gCol_1, undo_flags);
				gCol_1 = new_color;
				undo_flags |= UNDO_CONTINUE;	bUpdPG = true;
				}
			if(Dlg->GetColor(559, &new_color) && gCol_2 != new_color){
				Undo.ValDword(this, &gCol_2, undo_flags);
				gCol_2 = new_color;
				undo_flags |= UNDO_CONTINUE;	bUpdPG = true;
				}
			Dlg->GetValue(562, &transp);
			new_color = ((((int)(transp*2.55))<<24)&0xff000000);
			if(gTrans != new_color){
				Undo.ValDword(this, &gTrans, undo_flags);
				gTrans = new_color;
				undo_flags |= UNDO_CONTINUE;	bUpdPG = true;
				}
			if(Dlg->GetCheck(560)) n_gradient |= 0x10;
			else n_gradient &= ~0x10;
			if(n_gradient != grad_type) {
				Undo.ValInt(this, &grad_type, undo_flags);
				grad_type = n_gradient;
				undo_flags |= UNDO_CONTINUE;	bUpdPG = true;
				}
			if(bUpdPG){
				Command(CMD_UPDPG, 0L, 0L);		bRet= true;
				}
			}
		if(undo_flags & UNDO_CONTINUE) bRet= true;
		break;
		}
	if(brks && nbrk) free(brks);
	if(old_Label) free(old_Label);
	CloseDlgWnd(hDlg);
	delete Dlg;
	if(names) {
		for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
		free(names);
		}
	if(somePlots) free(somePlots);		free(AxisPropDlg);
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Graph dialogs
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static char *AddPlotTmpl =
		"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
		"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
		"3,,520,ISPARENT | CHECKED,GROUPBOX,1,5,10,135,95\n"
		"520,521,,EXRADIO | CHECKED,ODBUTTON,2,10,20,25,25\n"
		"521,522,,EXRADIO,ODBUTTON,2,35,20,25,25\n"
		"522,523,,EXRADIO,ODBUTTON,2,60,20,25,25\n"
		"523,524,,EXRADIO,ODBUTTON,2,85,20,25,25\n"
		"524,525,,EXRADIO,ODBUTTON,2,110,20,25,25\n"
		"525,526,,EXRADIO,ODBUTTON,2,10,45,25,25\n"
		"526,528,,EXRADIO,ODBUTTON,2,35,45,25,25\n"
		"528,529,,EXRADIO,ODBUTTON,2,60,45,25,25\n"
		"529,530,,EXRADIO,ODBUTTON,2,85,45,25,25\n"
		"530,531,,EXRADIO,ODBUTTON,2,110,45,25,25\n"
		"531,532,,EXRADIO,ODBUTTON,2,10,70,25,25\n"
		"532,540,,EXRADIO,ODBUTTON,2,35,70,25,25\n"
		"540,541,,EXRADIO,ODBUTTON,2,60,70,25,25\n"
		"541,,,LASTOBJ | EXRADIO,ODBUTTON, 2, 85,70,25,25";

bool
Graph::AddPlot(int family)
{
	void *dyndata[] = {(void *)"  select template  ",(void*)OD_PlotTempl};
	DlgInfo *GraphDlg = CompileDialog(AddPlotTmpl, dyndata);
	DlgRoot *Dlg;
	void *hDlg;
	int i, res, cSel = 520;
	bool bRet = false;
	Plot *p;

	switch(type) {
	case GT_STANDARD:
		break;
	case GT_POLARPLOT:
		for(i = 0; i < NumPlots; i++) {
			if(Plots[i] && Plots[i]->Id == GO_POLARPLOT) {
				if (((PolarPlot*)Plots[i])->AddPlot()) 
					return Command(CMD_REDRAW, 0L, 0L);
				}
			}
		return false;
	default:
		InfoBox("Don\'t know how to\nadd a plot to the\ncurrent graph.");
		return false;
		}
	Dlg = new DlgRoot(GraphDlg, data);		Dlg->bModal = false;
	hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 240, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 520:	case 521:	case 522:	case 523:	case 524:
		case 525:	case 526:	case 528:	case 529:	case 530:
		case 531:	case 532:	case 540:	case 541:
			if(res == cSel) res = 1;
			else {
				cSel = res;				res = -1;
				}
			break;
			}
		}while (res < 0);
	if(res == 1){						//OK pressed
		if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
		else if(Dlg->GetCheck(525)) p = new BoxPlot(this, data);
		else if(Dlg->GetCheck(521)) p = new PlotScatt(this, data, 0x03);
		else if(Dlg->GetCheck(522)) p = new PlotScatt(this, data, 0x08);
		else if(Dlg->GetCheck(523)) p = new PlotScatt(this, data, 0x04);
		else if(Dlg->GetCheck(526)) p = new Regression(this, data);
		else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
		else if(Dlg->GetCheck(529)) p = new Function(this, data, "Function");
		else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
		else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
		else if(Dlg->GetCheck(532)) p = new xyStat(this, data);
		else if(Dlg->GetCheck(540)) p = new StackBar(this, data);
		else if(Dlg->GetCheck(541)) p = new StackPG(this, data);
		else p = new PlotScatt(this, data, 0x01);
		if(p && p->PropertyDlg()) {
			if(!Command(CMD_DROP_PLOT, p, (anyOutput *)NULL)) delete p;
			else bRet = true;
			}
		else if(p) delete p;
		}
	CloseDlgWnd(hDlg);		delete Dlg;		free(GraphDlg);
	return bRet;
}

static char *GraphDlgTmpl = 
		"1,+,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
		".,.,,,PUSHBUTTON,-2,170,25,45,12\n"
		".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
		"4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,157,122\n"
		".,.,200,ISPARENT,SHEET,2,5,10,157,122\n"
		".,,300,ISPARENT,SHEET,3,5,10,157,122\n"
		"100,+,,,LTEXT,4,10,25,60,8\n"
		".,.,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
		".,.,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
		".,.,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
		".,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
		"200,+,,,LTEXT,9,10,35,60,8\n"
		".,.,,,RTEXT,10,5,47,58,8\n"
		".,.,,,EDVAL1,11,64,47,30,10\n"
		".,.,,,RTEXT,-5,95,47,10,8\n"
		".,.,,,EDVAL1,12,107,47,30,10\n"
		".,.,,,LTEXT,-3,140,47,20,8\n"
		".,.,,,RTEXT,13,5,59,58,8\n"
		".,.,,,EDVAL1,14,64,59,30,10\n"
		".,.,,,RTEXT,-5,95,59,10,8\n"
		".,.,,,EDVAL1,15,107,59,30,10\n"
		".,.,,,LTEXT,-3,140,59,20,8\n"
		".,.,,,LTEXT,16,10,84,60,8\n"
		".,.,,,RTEXT,17,5,96,58,8\n"
		".,.,,,EDVAL1,18,64,96,30,10\n"
		".,.,,,RTEXT,-5,95,96,10,8\n"
		".,.,,,EDVAL1,19,107,96,30,10\n"
		".,.,,,LTEXT,-3,140,96,20,8\n"
		".,.,,,RTEXT,20,5,108,58,8\n"
		".,.,,,EDVAL1,21,64,108,30,10\n"
		".,.,,,RTEXT,-5,95,108,10,8\n"
		".,.,,,EDVAL1,22,107,108,30,10\n"
		".,,,,LTEXT,-3,140,108,20,8\n"
		"300,+,,,LTEXT,23,20,30,60,8\n"
		".,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
		"310,+,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
		".,.,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
		".,.,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
		".,.,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
		".,.,,EXRADIO,ODBUTTON,24,120,42,25,25\n"
		".,.,,CHECKED | TOUCHEXIT,RADIO1, 25, 12,85,40,8\n"
		".,.,,TOUCHEXIT,RADIO1,26,12,93,40,8\n"
		".,.,,TOUCHEXIT,RADIO1,27,12,101,40,8\n"
		".,.,,TOUCHEXIT,CHECKBOX,28,80,85,40,8\n"
		".,,,TOUCHEXIT, CHECKBOX,29,80,93,40,8\n"
		"400,,410,HIDDEN | CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
		"410,+,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
		".,.,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
		".,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
		"500,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,95,85,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,120,85,25,25\n"
		".,,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
		"520,+,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,120,50,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,20,75,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,75,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,75,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,95,75,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,120,75,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
		".,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
		"540,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
		".,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
		"560,+,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,120,60,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
		".,.,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
		".,,,LASTOBJ | EXRADIO, ODBUTTON,31,95,85,25,25";

static int selSheet = 102, selPlt = 520, selAxis = 310;
bool
Graph::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Data"};
	TabSHEET tab2 = {22, 62, 10, "Placement"};
	TabSHEET tab3 = {62, 87, 10, "Axes"};
	TabSHEET tab_A = {0, 27, 10, "only Y"};
	TabSHEET tab_B = {27, 65, 10, "XY values"};
	TabSHEET tab_C = {65, 104, 10, "X, many Y"};
	TabSHEET tab_D = {104, 147, 10, "XYZ values"};
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"arrangement of data: select plot",
		(void*)&tab_A, (void*)&tab_B, (void*)&tab_C, (void*)&tab_D, (void*)"bounding rectangle (relative to page)",
		(void*)"upper left corner x", (void*)&GRect.Xmin, (void*)&GRect.Ymin, (void*)"lower right x",
		(void*)&GRect.Xmax, (void*)&GRect.Ymax, (void*)"plotting rectangle (relative to bounding rectangle)",
		(void*)"upper left corner x", (void*)&DRect.Xmin, (void*)&DRect.Ymin, (void*)"lower right x",
		(void*)&DRect.Xmax, (void*)&DRect.Ymax, (void*)"select template:", (void*)(OD_AxisTempl),
		(void*)"ticks outside", (void*)"ticks inside", (void*)"ticks symmetrical", (void*)"horizontal grid lines",
		(void*)"vertical grid lines", (void*)(OD_AxisTempl3D), (void*)(OD_PlotTempl)};
	DlgInfo *GraphDlg = CompileDialog(GraphDlgTmpl, dyndata);
	DlgRoot *Dlg;
	GraphObj *p;
	void *hDlg;
	int i, res;
	bool bRet, bContinue;
	fRECT rc1, rc2;

	ODtickstyle = tickstyle;
	AxisTempl = 0;
	if(!parent) return false;
	Dlg = new DlgRoot(GraphDlg, data);	Dlg->bModal = false;
	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
	if(parent->Id != GO_PAGE) {
		Dlg->Activate(202, false);	Dlg->Activate(204, false);
		}
	//restore previous settitings
	switch(selSheet) {
		case 101:
			if(selPlt >= 500 && selPlt <=507) Dlg->SetCheck(selPlt, 0L, true);
			else Dlg->SetCheck(500, 0L, true);
			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(540, 0L, true);
			Dlg->SetCheck(560, 0L, true);		break;
		default:
			if(selPlt >= 520 && selPlt <=532) Dlg->SetCheck(selPlt, 0L, true);
			else Dlg->SetCheck(520, 0L, true);	selSheet = 102;
			Dlg->SetCheck(500, 0L, true);		Dlg->SetCheck(540, 0L, true);
			Dlg->SetCheck(560, 0L, true);		break;
		case 103:
			if(selPlt >= 540 && selPlt <=544) Dlg->SetCheck(selPlt, 0L, true);
			else Dlg->SetCheck(540, 0L, true);
			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(500, 0L, true);
			Dlg->SetCheck(560, 0L, true);		break;
		case 104:
			if(selPlt >= 560 && selPlt <=568) Dlg->SetCheck(selPlt, 0L, true);
			else Dlg->SetCheck(560, 0L, true);
			Dlg->ShowItem(301, false);	Dlg->ShowItem(400, true);
			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(540, 0L, true);
			Dlg->SetCheck(500, 0L, true);		break;
		}
	Dlg->SetCheck(selSheet, 0L, true);
	if(selAxis >= 310 && selAxis <= 314) Dlg->SetCheck(selAxis, 0L, true);
	else Dlg->SetCheck(310, 0L, true);
	if(selAxis >= 410 && selAxis <= 412) Dlg->SetCheck(selAxis, 0L, true);
	else Dlg->SetCheck(410, 0L, true);
	//display the dialog
	hDlg = CreateDlgWnd("Create graph", 50, 50, 450, 300, Dlg, 0x4L);
	bContinue = false;
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		bRet = false;
		switch(res) {
		case 0:
			if(bContinue) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 101:	//only y data
			for(i = 500; i <= 506; i++) if(Dlg->GetCheck(i))selPlt = i;
			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
			selSheet = res;				res = -1;
			break;
		case 102:	//xy data
			for(i = 520; i <= 532; i++) if(Dlg->GetCheck(i))selPlt = i;
			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
			selSheet = res;				res = -1;
			break;
		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);
			selSheet = res;				res = -1;
			break;
		case 104:	//xyz data
			for(i = 560; i <= 567; i++) if(Dlg->GetCheck(i))selPlt = i;
			Dlg->ShowItem(301, false);	Dlg->ShowItem(400, true);
			selSheet = res;				res = -1;
			break;
		case 310:	case 311:	case 312:	case 313:	case 314:
			AxisTempl = res-310;
			if(res == selAxis) Dlg->SetCheck(4, 0L, true);
			selAxis = res;
			res = -1;
			break;
		case 315:	case 316:	case 317:	//tick style
			tickstyle = res -315;
		case 318:	case 319:				//horizontal or vertical grid
			tickstyle &= ~0x300;
			if(Dlg->GetCheck(318)) tickstyle |= 0x200;
			if(Dlg->GetCheck(319)) tickstyle |= 0x100;
			ODtickstyle = tickstyle;
			Dlg->DoPlot(0L);
			res = -1;
			break;
		case 410:	case 411:	case 412:	//axis templates
			AxisTempl3D = res-410;
			res = -1;
			break;
		case 500:	case 501:	case 502:	case 503:
		case 504:	case 505:	case 506:	case 507:
		case 520:	case 521:	case 522:	case 523:
		case 524:	case 525:	case 526:	case 527:
		case 528:	case 529:	case 530:	case 531:	case 532:
		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 567:	case 568:
			if(res != selPlt) {
				selPlt = res;
				res = -1;
				break;
				}
			//double click means select: continue as if OK
			res = 1;
		case 1:
			if(!Dlg->GetCheck(4)) {
				Dlg->SetCheck(4, 0L, true);
				res = -1;
				break;
				}
			memcpy(&rc1, &GRect, sizeof(fRECT));
			memcpy(&rc2, &DRect, sizeof(fRECT));
			Dlg->GetValue(202, &rc1.Xmin);			Dlg->GetValue(204, &rc1.Ymin);
			Dlg->GetValue(207, &rc1.Xmax);			Dlg->GetValue(209, &rc1.Ymax);
			Dlg->GetValue(213, &rc2.Xmin);			Dlg->GetValue(215, &rc2.Ymin);
			Dlg->GetValue(218, &rc2.Xmax);			Dlg->GetValue(220, &rc2.Ymax);
			if(rc1.Xmin < 0.0 || rc1.Xmax < 0.0 || rc1.Ymin < 0.0 || 
				rc1.Ymax < 0.0 || rc2.Xmin < 0.0 || rc2.Xmax < 0.0 || 
				rc2.Ymin < 0.0 || rc2.Ymax < 0.0) {
				ErrorBox("All values defining\nthe placement of the plot\n"
					"must be positive.");
				res = -1;
				bContinue = true;
				Dlg->SetCheck(5, 0L, true);
				break;
				}
			if(rc2.Xmin > (rc1.Xmax-rc1.Xmin) || rc2.Ymax > (rc1.Ymax-rc1.Ymin) 
				|| (rc2.Xmax-rc2.Xmin) > (rc1.Xmax-rc1.Xmin)
				|| (rc2.Ymax-rc2.Ymin) > (rc1.Ymax-rc1.Ymin)){
				ErrorBox("The plotting rectangle must\nfit inside the\n"
					"bounding rectangle.");
				res = -1;
				bContinue = true;
				Dlg->SetCheck(5, 0L, true);
				break;
				}
			memcpy(&GRect, &rc1, sizeof(fRECT));
			memcpy(&DRect, &rc2, sizeof(fRECT));
			p = 0L;
			if(Dlg->GetCheck(101)) {
				if(Dlg->GetCheck(500))p = new PieChart(this, data);
				else if(Dlg->GetCheck(501))p = new RingChart(this, data);
				else if(Dlg->GetCheck(502))p = new StarChart(this, data);
				else if(Dlg->GetCheck(503))p = new BarChart(this, data);
				else if(Dlg->GetCheck(504))p = new GroupBars(this, data, 0);
				else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
				else if(Dlg->GetCheck(506))p = new NormQuant(this, data, 0L);
				else if(Dlg->GetCheck(507))p = new GroupBars(this, data, 1);
				}
			else if(Dlg->GetCheck(102)){
				if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
				else if(Dlg->GetCheck(525)) p = new BoxPlot(this, data);
				else if(Dlg->GetCheck(521)) p = new PlotScatt(this, data, 0x03);
				else if(Dlg->GetCheck(522)) p = new PlotScatt(this, data, 0x08);
				else if(Dlg->GetCheck(523)) p = new PlotScatt(this, data, 0x04);
				else if(Dlg->GetCheck(526)) p = new Regression(this, data);
				else if(Dlg->GetCheck(527)) p = new PolarPlot(this, data);
				else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
				else if(Dlg->GetCheck(529)) p = new Function(this, data, "Function");
				else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
				else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
				else if(Dlg->GetCheck(532)) p = new xyStat(this, data);
				else p = new PlotScatt(this, data, 0x01);
				}
			else if(Dlg->GetCheck(103)) {
				if(Dlg->GetCheck(540)) p = new StackBar(this, data);
				else if(Dlg->GetCheck(542)) p = new Waterfall(this, data);
				else if(Dlg->GetCheck(543)) p = new Chart25D(this, data, 0L);
				else if(Dlg->GetCheck(544)) p = new Ribbon25D(this, data, 0L);
				else p = new StackPG(this, data);
				}
			else if(Dlg->GetCheck(104)) {
				if(Dlg->GetCheck(560)) p = new Plot3D(this, data, 0x1001);
				else if(Dlg->GetCheck(561)) p = new Plot3D(this, data, 0x1002);
				else if(Dlg->GetCheck(562)) p = new Plot3D(this, data, 0x1004);
				else if(Dlg->GetCheck(563)) p = new BubblePlot3D(this, data);
				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);
				else if(Dlg->GetCheck(568)) p = new ContourPlot(this, data);
				}
			if(p && p->PropertyDlg()) {
				if(!Command(CMD_DROP_PLOT, p, 0L)) DeleteGO(p);
				else bRet = true;
				}
			else if(p) {
				Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
				DeleteGO(p);		Dlg->DoPlot(0L);			ShowDlgWnd(hDlg);
				}
			if(!bRet) {
				res = -1;
				//we might have lost the focus
				bContinue = true;
				}
			break;
			}
		}while(res <0);
	Command(CMD_SET_DATAOBJ, (void*)data, 0L);
	CloseDlgWnd(hDlg);		delete Dlg;		free(GraphDlg);
	return bRet;
}

bool
Graph::Configure()
{
	TabSHEET tab1 = {0, 28, 10, "Colors"};
	TabSHEET tab2 = {28, 68, 10, "Placement"};
	DlgInfo GraphDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Add Plot", 170, 73, 45, 12},
		{4, 5, 0, 0x0L, PUSHBUTTON, (void*)"Add Axis", 170, 88, 45, 12},
		{5, 6, 0, 0x0L, PUSHBUTTON, (void*)"Add Legend", 170, 103, 45, 12},
		{6, 13, 0, 0x0L, PUSHBUTTON, (void*)"Layers", 170, 118, 45, 12},
		{13, 50, 14, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
		{14, 15, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 155, 120},
		{15, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 155, 120},
		{50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
		{100, 101, 0, 0x0L, LTEXT, (void*)"bounding rectangle", 20, 30, 60, 8},
		{101, 102, 0, 0x0L, RTEXT, (void*)"fill color", 15, 42, 58, 8},
		{102, 103, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColGR, 74, 42, 25, 10},
		{103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 15, 54, 58, 8},
		{104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColGRL, 74, 54, 25, 10},
		{105, 106, 0, 0x0L, LTEXT, (void*)"plotting rectangle", 20, 68, 60, 8},
		{106, 107, 0, 0x0L, RTEXT, (void*)"fill color", 15, 80, 58, 8},
		{107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColDR, 74, 80, 25, 10},
		{108, 109, 0, 0x0L, LTEXT, (void*)"axes, ticks, and axis labels", 20, 94, 60, 8},
		{109, 110, 0, 0x0L, RTEXT, (void*)"axis color", 15, 106, 58, 8},
		{110, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (void *)&ColAX, 74, 106, 25, 10},
		{200, 201, 0, 0x0L, LTEXT, (void*)"bounding rectangle (relative to page)", 10, 35, 60, 8},
		{201, 202, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 47, 58, 8},
		{202, 203, 0, 0x0L, EDVAL1, &GRect.Xmin, 64, 47, 30, 10},
		{203, 204, 0, 0x0L, RTEXT, (void*)"y", 95, 47, 10, 8},
		{204, 205, 0, 0x0L, EDVAL1, &GRect.Ymin, 107, 47, 30, 10},
		{205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 47, 20, 8},
		{206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 59, 58, 8},
		{207, 208, 0, 0x0L, EDVAL1, &GRect.Xmax, 64, 59, 30, 10},
		{208, 209, 0, 0x0L, RTEXT, (void*)"y", 95, 59, 10, 8},
		{209, 210, 0, 0x0L, EDVAL1, &GRect.Ymax, 107, 59, 30, 10},
		{210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 59, 20, 8},
		{211, 212, 0, 0x0L, LTEXT, (void*)"plotting rectangle (relative to bounding rectangle)", 10, 84, 60, 8},
		{212, 213, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 96, 58, 8},
		{213, 214, 0, 0x0L, EDVAL1, &DRect.Xmin, 64, 96, 30, 10},
		{214, 215, 0, 0x0L, RTEXT, (void*)"y", 95, 96, 10, 8},
		{215, 216, 0, 0x0L, EDVAL1, &DRect.Ymin, 107, 96, 30, 10},
		{216, 217, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 96, 20, 8},
		{217, 218, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 108, 58, 8},
		{218, 219, 0, 0x0L, EDVAL1, &DRect.Xmax, 64, 108, 30, 10},
		{219, 220, 0, 0x0L, RTEXT, (void*)"y", 95, 108, 10, 8},
		{220, 221, 0, 0x0L, EDVAL1, &DRect.Ymax, 107, 108, 30, 10},
		{221, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 108, 20, 8},
		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 40, 15, 15},
		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 190, 40, 15, 15},
		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 190, 55, 15, 15},
		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 55, 15, 15}};
	DlgRoot *Dlg;
	void *hDlg;
	int i, res, undo_level = *Undo.pcb;
	DWORD undo_flags = 0, tmpcol;
	anyOutput *cdisp = Undo.cdisp;
	bool bRet = false, bContinue = false;
	fRECT o_gr, n_gr, o_dr, n_dr;

	if(!(Dlg = new DlgRoot(GraphDlg, data)))return false;
	Dlg->GetValue(202, &o_gr.Xmin);			Dlg->GetValue(204, &o_gr.Ymin);
	Dlg->GetValue(207, &o_gr.Xmax);			Dlg->GetValue(209, &o_gr.Ymax);
	Dlg->GetValue(213, &o_dr.Xmin);			Dlg->GetValue(215, &o_dr.Ymin);
	Dlg->GetValue(218, &o_dr.Xmax);			Dlg->GetValue(220, &o_dr.Ymax);
	if(parent && parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name ? name : (char*)"Graph");
	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, (char*)" properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 450, 300, Dlg, 0x4L);
	do{
		LoopDlgWnd();			res = Dlg->GetResult();
		switch (res) {
		case 600:	case 601:	case 602:	case 603:
			Undo.SetDisp(cdisp);
			res = ExecDrawOrderButt(parent, this, res);
			}
		switch(res) {
		case 0:
			if(bContinue) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 102:	case 104:	case 107:	case 110:
			res = -1;
			break;
		case 1:
			Dlg->GetValue(202, &n_gr.Xmin);			Dlg->GetValue(204, &n_gr.Ymin);
			Dlg->GetValue(207, &n_gr.Xmax);			Dlg->GetValue(209, &n_gr.Ymax);
			Dlg->GetValue(213, &n_dr.Xmin);			Dlg->GetValue(215, &n_dr.Ymin);
			Dlg->GetValue(218, &n_dr.Xmax);			Dlg->GetValue(220, &n_dr.Ymax);
			if(n_gr.Xmin < 0.0 || n_gr.Xmax < 0.0 || n_gr.Ymin < 0.0 || 
				n_gr.Ymax < 0.0 || n_dr.Xmin < 0.0 || n_dr.Xmax < 0.0 || 
				n_dr.Ymin < 0.0 || n_dr.Ymax < 0.0) {
				ErrorBox("All values defining\nthe placement of the plot\n"
					"must be positive.");
				res = -1;
				bContinue = true;
				Dlg->SetCheck(5, 0L, true);
				break;
				}
			if(n_dr.Xmin > (n_gr.Xmax-n_gr.Xmin) || n_dr.Ymax > (n_gr.Ymax-n_gr.Ymin) 
				|| (n_dr.Xmax-n_dr.Xmin) > (n_gr.Xmax-n_gr.Xmin)
				|| (n_dr.Ymax-n_dr.Ymin) > (n_gr.Ymax-n_gr.Ymin)){
				ErrorBox("The plotting rectangle must\nfit inside the\n"
					"bounding rectangle.");
				res = -1;
				bContinue = true;
				Dlg->SetCheck(5, 0L, true);
				break;
				}
			bRet = true;
			break;
		case 3:
			if(bRet = Command(CMD_ADDPLOT, 0L, 0L)) break;
		case 4:
			if(res == 4 && (bRet = Command(CMD_ADDAXIS, 0L, 0L))) break;
			bContinue = true;
			res = -1;
			break;
		case 5:
			Command(CMD_LEGEND, 0L, 0L);
			break;
		case 6:
			Command(CMD_LAYERS, 0L, 0L);
			bContinue = true;
			res = -1;
			break;
			}
		}while(res <0);
	if(res == 1 && bRet) {
		Undo.SetDisp(cdisp);
		if(n_gr.Xmin != o_gr.Xmin || n_gr.Xmax != o_gr.Xmax ||
			n_gr.Ymin != o_gr.Ymin || n_gr.Ymax != o_gr.Ymax ||
			n_dr.Xmin != o_dr.Xmin || n_dr.Xmax != o_dr.Xmax ||
			n_dr.Ymin != o_dr.Ymin || n_dr.Ymax != o_dr.Ymax){
			Command(CMD_SAVEPOS, 0L, 0L);
			memcpy(&GRect, &n_gr, sizeof(fRECT));
			memcpy(&DRect, &n_dr, sizeof(fRECT));
			undo_flags |= UNDO_CONTINUE;
			}
		if(Dlg->GetColor(102, &tmpcol))
			undo_flags = CheckNewDword(&ColGR, ColGR, tmpcol, this, undo_flags);
		if(Dlg->GetColor(104, &tmpcol))
			undo_flags = CheckNewDword(&ColGRL, ColGRL, tmpcol, this, undo_flags);
		if(Dlg->GetColor(107, &tmpcol))
			undo_flags = CheckNewDword(&ColDR, ColDR, tmpcol, this, undo_flags);
		if(Dlg->GetColor(110, &tmpcol) && tmpcol != ColAX) {
			undo_flags = CheckNewDword(&ColAX, ColAX, tmpcol, this, undo_flags);
			if(Axes) for(i = 0; i < NumAxes; i++)
				if(Axes[i]) Axes[i]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
			if(Plots && NumPlots && Plots[0] && (Plots[0]->Id == GO_PLOT3D || Plots[0]->Id == GO_FUNC3D)) 
				Plots[0]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
			}
		}
	else if(res == 2) {
		Undo.SetDisp(cdisp);
		if(*Undo.pcb > undo_level) {	//restore plot order
			while(*Undo.pcb > undo_level)	Undo.Restore(false, 0L);
			bRet = true;
			}
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

static char *AddAxisTmpl =
	"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,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,130\n"
	"5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,130\n"
	"6,,300,ISPARENT,SHEET,3,5,10,130,130\n"
	"50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
	"51,120,,,CHECKBOX,5,17,37,80,8\n"
	"100,101,,,RTEXT,6,10,51,35,8\n"
	"101,102,,,EDVAL1,7,48,51,32,10\n"
	"102,103,,,CTEXT,8,81,51,11,8\n"
	"103,,,,EDVAL1,9,93,51,32,10\n"
	"120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
	"121,122,,,RTEXT,11,10,77,25,8\n"
	"122,123,,,EDVAL1,12,37,77,25,10\n"
	"123,124,,,LTEXT,-3,63,77,10,8\n"
	"124,125,,,RTEXT,-11,73,77,25,8\n"
	"125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
	"130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
	"131,,,,EDTEXT,0,15,103,110,10\n"
	"200,201,,,LTEXT,16,10,30,70,9\n"
	"201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,42,25,25\n"
	"202,203,,EXRADIO,ODBUTTON,17,45,42,25,25\n"
	"203,204,,EXRADIO,ODBUTTON,17,70,42,25,25\n"
	"204,205,,EXRADIO,ODBUTTON,17,95,42,25,25\n"
	"205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
	"206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
	"207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
	"208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
	"210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
	"220,221,,,RTEXT,-4,10,105,15,8\n"
	"221,222,,,EDVAL1,19,27,105,35,10\n"
	"222,223,,,LTEXT,-7,65,105,5,8\n"
	"223,224,,,EDVAL1,20,71,105,35,10\n"
	"224,225,,,LTEXT,-3,109,105,15,8\n"
	"225,226,,,RTEXT,-5,10,117,15,8\n"
	"226,227,,,EDVAL1,21,27,117,35,10\n"
	"227,228,,,LTEXT,-7,65,117,5,8\n"
	"228,229,,,EDVAL1,22,71,117,35,10\n"
	"229,,,,LTEXT,-3,109,117,15,8\n"
	"300,,,LASTOBJ | NOSELECT,ODBUTTON,23,15,30,110,140";

bool
Graph::AddAxis()
{
	TabSHEET tab1 = {0, 25, 10, "Axis"};
	TabSHEET tab2 = {25, 52, 10, "Style"};
	TabSHEET tab3 = {52, 78, 10, "Plots"};
	AxisDEF axis;
	double sizAxLine = DefSize(SIZE_AXIS_LINE);
	DWORD colAxis = ColAX;
	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
		(void*)"axis from", (void*)&y_axis.min, (void*)"to", (void*)&y_axis.max, (void*)" line ", (void*)"width",
		(void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
		(void*)(OD_NewAxisTempl), (void*)" placement ", (void*)&axis.loc[0].fx, (void*)&axis.loc[1].fx,
		(void*)&axis.loc[0].fy, (void*)&axis.loc[1].fy,  (void*)OD_axisplot};
	DlgInfo *NewAxisDlg;
	DlgRoot *Dlg;
	void *hDlg;
	int i, j, res, currTempl = 201;
	double vx1, vx2, vy1, vy2, hx1, hx2, hy1, hy2;
	double tlb_dist, tlb_dx, tlb_dy, lb_x, lb_y;
	TextDEF label_def, tlbdef;
	DWORD flags;
	anyOutput *cdisp = Undo.cdisp;
	Axis *the_new, **tmpAxes;
	bool bAxis = false, bRet = false;
	char **names;
	GraphObj **somePlots;
	Label *label;

	if(!(NewAxisDlg = CompileDialog(AddAxisTmpl, dyndata)))return false;
	if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
	if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
	if(!Axes) Axes = (Axis**)calloc(2, sizeof(Axis*));
	if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
	for(i = 0, j = 1; i < nscp; i++) {
		if(Sc_Plots[i] && Sc_Plots[i]->name){
			names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
			somePlots[j++] = Sc_Plots[i];
			}
		}
	OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
	axis.loc[0].fx = axis.loc[1].fx = vx1 = vx2 = (DRect.Xmin + DRect.Xmax)/2.0;
	axis.loc[0].fy = vy1 = DRect.Ymin;
	axis.loc[1].fy = vy2 = DRect.Ymax;
	axis.min = y_axis.min;		axis.max = y_axis.max;
	hy1 = hy2 = (DRect.Ymax + DRect.Ymin)/2.0;
	hx1 = DRect.Xmin;			hx2 = DRect.Xmax;
	if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
	if(type != 1 || !nscp){		//must be standard graph to link to plot
		Dlg->ShowItem(6, false);
		}
	hDlg = CreateDlgWnd("New axis properties", 50, 50, 400, 318, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch (res){
		case 4:											//the axis sheet
			res = -1;
			bAxis = true;
			break;
		case 201:	case 202:	case 203:	case 204:	//axis templates
		case 205:	case 206:	case 207:	case 208:
			if(currTempl > 204) {
				Dlg->GetValue(221, &hx1);				Dlg->GetValue(223, &hx2);
				Dlg->GetValue(226, &hy1);				Dlg->GetValue(228, &hy2);
				}
			else {
				Dlg->GetValue(221, &vx1);				Dlg->GetValue(223, &vx2);
				Dlg->GetValue(226, &vy1);				Dlg->GetValue(228, &vy2);
				}
			if(res > 204) {
				Dlg->SetValue(221, hx1);				Dlg->SetValue(223, hx2);
				Dlg->SetValue(226, hy1);				Dlg->SetValue(228, hy2);
				if(! bAxis) {
					Dlg->SetValue(101, x_axis.min);		Dlg->SetValue(103, x_axis.max);
					}
				}
			else {
				Dlg->SetValue(221, vx1);				Dlg->SetValue(223, vx2);
				Dlg->SetValue(226, vy1);				Dlg->SetValue(228, vy2);
				if(! bAxis) {
					Dlg->SetValue(101, y_axis.min);		Dlg->SetValue(103, y_axis.max);
					}
				}
			currTempl = res;
			Dlg->DoPlot(0L);
			res = -1;
			break;
			}
		}while (res < 0);
	if(res == 1) {
		Undo.SetDisp(cdisp);
		Dlg->GetValue(122, &sizAxLine);				Dlg->GetColor(125, &colAxis);
		Dlg->GetValue(221, &axis.loc[0].fx);		Dlg->GetValue(223, &axis.loc[1].fx);
		Dlg->GetValue(226, &axis.loc[0].fy);		Dlg->GetValue(228, &axis.loc[1].fy);
		axis.loc[0].fz = axis.loc[1].fz = 0.0;		axis.owner = 0L;
		Dlg->GetValue(101, &axis.min);				Dlg->GetValue(103, &axis.max);
		axis.Start = axis.min;				axis.Center.fx = axis.Center.fy = 0.0;
		axis.nBreaks = 0;			axis.breaks = 0L;		axis.Radius = 0.0;	
		tlb_dist = NiceValue(DefSize(SIZE_AXIS_TICKS));
		tlb_dx = tlb_dy = 0.0;
		tlbdef.ColTxt = colAxis;				tlbdef.ColBg = 0x00ffffffL;
		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
		tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
		tlbdef.Style = TXS_NORMAL;				tlbdef.Mode = TXM_TRANSPARENT;
		tlbdef.Font = FONT_HELVETICA;			tlbdef.text = 0L;
		label_def.ColTxt = colAxis;				label_def.ColBg = 0x00ffffffL;
		label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2f;	label_def.RotBL = 0.0f;
		label_def.RotCHAR = 0.0f;								label_def.iSize = 0;
		label_def.Align = TXA_VTOP | TXA_HCENTER;		label_def.Mode = TXM_TRANSPARENT;
		label_def.Style = TXS_NORMAL;	label_def.Font = FONT_HELVETICA;
		switch (currTempl) {
		default:	flags = AXIS_NEGTICKS;	axis.Step = y_axis.Step;
			tlb_dx = -tlb_dist * 2.0;	tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
			lb_x = -tlb_dist * 6.0;		lb_y = 0;	label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
			label_def.RotBL = 90.0;
			break;
		case 202:	flags = AXIS_POSTICKS;	axis.Step = y_axis.Step;
			tlb_dx = -tlb_dist;			tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
			lb_x = -tlb_dist * 4.5;		lb_y = 0;	label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
			label_def.RotBL = 90.0;
			break;
		case 203:	flags = AXIS_POSTICKS;	axis.Step = y_axis.Step;
			tlb_dx = tlb_dist * 2.0;	tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
			lb_x = tlb_dist * 6;		lb_y = 0;	label_def.Align = TXA_VTOP | TXA_HCENTER;
			label_def.RotBL = 90.0;
			break;
		case 204:	flags = AXIS_NEGTICKS;	axis.Step = y_axis.Step;
			tlb_dx = tlb_dist;			tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
			lb_x = tlb_dist * 4.5;		lb_y = 0;	label_def.Align = TXA_VTOP | TXA_HCENTER;
			label_def.RotBL = 90.0;
			break;
		case 205:	flags = AXIS_NEGTICKS;	axis.Step = x_axis.Step;
			tlb_dy = tlb_dist * 2.0;	tlbdef.Align = TXA_VTOP | TXA_HCENTER;
			lb_x = 0;					lb_y = tlb_dist * 4.0;
			break;
		case 206:	flags = AXIS_POSTICKS;	axis.Step = x_axis.Step;
			tlb_dy = tlb_dist;			tlbdef.Align = TXA_VTOP | TXA_HCENTER;
			lb_x = 0;					lb_y = tlb_dist * 3.0;
			break;
		case 207:	flags = AXIS_POSTICKS;	axis.Step = x_axis.Step;
			tlb_dy = -tlb_dist * 2.0;	tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
			lb_x = 0;	lb_y = -tlb_dist * 4.0;	label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
			break;
		case 208:	flags = AXIS_NEGTICKS;	axis.Step = x_axis.Step;
			tlb_dy = -tlb_dist;			tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
			lb_x = 0;	lb_y = -tlb_dist * 3.0;	label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
			break;
			}
		flags |= AXIS_AUTOTICK;			flags |= AXIS_DEFRECT;
		if(Dlg->GetCheck(51)) flags |= AXIS_AUTOSCALE;
		if(the_new = new Axis(this, data, &axis, flags)){
			the_new->SetSize(SIZE_TLB_YDIST, tlb_dy);	the_new->SetSize(SIZE_TLB_XDIST, tlb_dx); 
			the_new->SetSize(SIZE_AXIS_LINE, sizAxLine);
			the_new->SetColor(COL_AXIS, colAxis);
			the_new->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
			the_new->SetSize(SIZE_LB_XDIST, lb_x);		the_new->SetSize(SIZE_LB_YDIST, lb_y); 
			if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) label_def.text = TmpTxt;
			else label_def.text = 0L;
			if(label = new Label(Axes[0], data, (axis.loc[0].fx + axis.loc[1].fx)/2.0,
				(axis.loc[0].fy + axis.loc[1].fy)/2.0, &label_def, 
				label_def.RotBL < 45.0 ? LB_Y_PARENT : LB_X_PARENT)){
				label->SetSize(SIZE_LB_XDIST, lb_x);	label->SetSize(SIZE_LB_YDIST, lb_y); 
				if(the_new->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
				else DeleteGO(label);
				}
			for(i = 0; i < NumAxes && Axes[i]; i++);
			if(i < NumAxes) {
				Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
				bRet = true;
				}
			else {
				if(tmpAxes = (Axis**)calloc(NumAxes+1, sizeof(Axis*))){
					memcpy(tmpAxes, Axes, NumAxes * sizeof(Axis*));
					Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, NumAxes);
					Undo.SetGO(this, (GraphObj**)(&tmpAxes[NumAxes]), the_new, 0L);
					free(Axes);			Axes = tmpAxes;
					i = NumAxes++;		bRet = true;
					}
				else delete (the_new);	//very unlikely memory allocation error
				}
			CurrAxes = Axes;
			if(bRet) {
				OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
				if(res && i) somePlots[res]->Command(CMD_USEAXIS, &i, 0L);
				}
			}
		}
	CloseDlgWnd(hDlg);		delete Dlg;			free(NewAxisDlg);
	if(names) {
		for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
		free(names);
		}
	if(somePlots) free(somePlots);
	return bRet;
}

bool
Page::Configure()
{
	TabSHEET tab1 = {0, 50, 10, "Paper Size"};
	DlgInfo PageDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 135, 10, 45, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 135, 25, 45, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
		{5, 0, 0, 0x0L, PUSHBUTTON, (void*)"Layers", 135, 118, 45, 12},
		{100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_paperdef, 15, 30, 110, 140}};
	DlgRoot *Dlg;
	void *hDlg;
	int res, cb;
	bool bRet = false, bContinue = false;

	FindPaper(GRect.Xmax - GRect.Xmin, GRect.Ymax -GRect.Ymin, .0001);
	if(!(Dlg = new DlgRoot(PageDlg, data)))return false;
	if(name)cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name);
	else cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Page");
	rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, " properties");
	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 380, 300, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(bContinue) res = -1;
			break;
		case -1:
			bContinue = false;
			break;
		case 5:
			Command(CMD_LAYERS, 0L, 0L);
			bContinue = true;
			res = -1;
			}
		}while(res <0);
	if(res == 1) {
		OD_paperdef(OD_ACCEPT, 0L, 0L, 0L, 0L, 0);
		GRect.Xmin = GRect.Ymin = 0.0;
		GetPaper(&GRect.Xmax, &GRect.Ymax);
		DoPlot(CurrDisp);
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Edit global defaults
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
Default::PropertyDlg()
{
	TabSHEET tab1 = {0, 22, 10, "Line"};
	TabSHEET tab2 = {22, 52, 10, "Shapes"};
	TabSHEET tab3 = {52, 82, 10, "Dialogs"};
	TabSHEET tab4 = {82, 116, 10, "Internat."};
	TabSHEET tab5 = {116, 155, 10, "Date/Time"};
	double ts =  dlgtxtheight;
	time_t ti = time(0L);
	char dt_info[50], date_info[50], datetime_info[50], time_info[50];
	DlgInfo DefsDlg[] = {
		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 180, 10, 40, 12},
		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 180, 25, 40, 12},
		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 170, 130},
		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 170, 130},
		{6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 170, 130},
		{7, 8, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 170, 130},
		{8, 0, 350, TOUCHEXIT | ISPARENT, SHEET, &tab5, 5, 10, 170, 130},
		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
		{200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 40, 90, 50},
		{300, 301, 0, 0x0L, RTEXT, (void*)"text size", 20, 30, 38, 8},
		{301, 302, 0, 0x0L, EDVAL1, (void*)&ts, 60, 30, 20, 10},
		{302, 0, 0, 0x0L, LTEXT, (void*)"pixel", 82, 30, 20, 8},
		{350, 351, 0, 0x0L, LTEXT, (void*)dt_info, 10, 30, 120, 8},
		{351, 352, 0, 0x0L, LTEXT, (void*)"date format:", 10, 43, 70, 8},
		{352, 353, 0, 0x0L, EDTEXT, (void*)defs.fmt_date, 10, 53, 60, 10},
		{353, 354, 0, 0x0L, LTEXT, (void*)date_info, 80, 54, 40, 10}, 
		{354, 355, 0, 0x0L, LTEXT, (void*)"date + time format:", 10, 65, 70, 8},
		{355, 356, 0, 0x0L, EDTEXT, (void*)defs.fmt_datetime, 10, 75, 60, 10},
		{356, 357, 0, 0x0L, LTEXT, (void*)datetime_info, 80, 76, 40, 10}, 
		{357, 358, 0, 0x0L, LTEXT, (void*)"time format:", 10, 87, 70, 8},
		{358, 359, 0, 0x0L, EDTEXT, (void*)defs.fmt_time, 10, 97, 60, 10},
		{359, 360, 0, 0x0L, LTEXT, (void*)time_info, 80, 98, 40, 10}, 
		{360, 361, 0, 0x0L, LTEXT, (void*)"For further information about formats see", 10, 119, 140, 8},
		{361, 362, 0, HREF | TOUCHEXIT, LTEXT, (void*)"http://rlplot.sourceforge.net/Docs/functions/datetime.html", 10, 127, 140, 8},
		{362, 0, 0, 0x0L, PUSHBUTTON, (void*)"Test", 130, 107, 40, 12},
		{400, 401, 0, 0x0L, LTEXT, (void*)"edit country specific information", 20, 30, 100, 8},
		{401, 402, 0, 0x0L, RTEXT, (void*)"decimal point", 45, 45, 40, 8},
		{402, 403, 0, 0x0L, EDTEXT, (void*)DecPoint, 90, 45, 10, 10},
		{403, 404, 0, 0x0L, RTEXT, (void*)"column separator", 45, 57, 40, 8},
		{404, 405, 0, 0x0L, EDTEXT, (void*)ColSep, 90, 57, 10, 10},
		{405, 406, 0, 0x0L, RTEXT, (void*)"use units:", 25, 75, 47, 8},
		{406, 0, 420, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
		{420, 421, 0, 0x0L, RADIO1, (void*)Units[0].display, 75, 75, 20, 8},
		{421, 422, 0, 0x0L, RADIO1, (void*)Units[1].display, 75, 83, 20, 8},
		{422, 0, 0, LASTOBJ, RADIO1, (void*)Units[2].display, 75, 91, 20, 8}};
	DlgRoot *Dlg;
	void *hDlg;
	int i, cb, res, tmpUnits = cUnits;
	bool bRet = false, bContinue = false;
	double dt;
	LineDEF LineDef;
	FillDEF FillDef;

	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)GetLine(), 0);
	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)GetOutLine(), 0);
	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)GetFill(), 0);
	cb = rlp_strcpy(dt_info, 20, "today is ");
#ifdef USE_WIN_SECURE
	ctime_s(dt_info+cb, 50-cb, &ti);
#else
	rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
#endif
	dt_info[cb+24] = 0;
	date_value(dt_info+13, "x z H:M:S Y", &dt);
	rlp_strcpy(date_info, 50, value_date(dt, defs.fmt_date));
	rlp_strcpy(datetime_info, 50, value_date(dt, defs.fmt_datetime));
	rlp_strcpy(time_info, 50, value_date(dt, defs.fmt_time));
	Dlg = new DlgRoot(DefsDlg, 0L);
	switch(dUnits) {
	case 1:		Dlg->SetCheck(421, 0L, true);	break;
	case 2:		Dlg->SetCheck(422, 0L, true);	break;
	default:	Dlg->SetCheck(420, 0L, true);	break;
		}
#ifdef _WINDOWS
	for(i = 360; i <= 361; i++) Dlg->TextSize(i, 12);
#else
	for(i = 360; i <= 361; i++) Dlg->TextSize(i, 10);
#endif
	hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 460, 316, Dlg, 0x4L);
	do{
		LoopDlgWnd();
		res = Dlg->GetResult();
		switch(res) {
		case 0:
			if(bContinue) res = -1;
			break;
		case 362:				//update date/time display
			ti = time(0L);		cb = rlp_strcpy(dt_info, 20, "today is ");
#ifdef USE_WIN_SECURE
			ctime_s(dt_info+cb, 50-cb, &ti);
#else
			rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
#endif
			dt_info[cb+24] = 0;												Dlg->SetText(350, dt_info);
			date_value(dt_info+13, "x z H:M:S Y", &dt);
			if(!(Dlg->GetText(352, date_info, 50))) rlp_strcpy(date_info, 50, defs.fmt_date);
			rlp_strcpy(date_info, 50, value_date(dt, date_info));			Dlg->SetText(353, date_info);
			if(!(Dlg->GetText(355, datetime_info, 50))) rlp_strcpy(datetime_info, 50, defs.fmt_datetime);
			rlp_strcpy(datetime_info, 50, value_date(dt, datetime_info));	Dlg->SetText(356, datetime_info);
			if(!(Dlg->GetText(358, time_info, 50))) rlp_strcpy(time_info, 50, defs.fmt_time);
			rlp_strcpy(time_info, 50, value_date(dt, time_info));			Dlg->SetText(359, time_info);
			bContinue = false;		res = -1;
			break;
		case 361:			//call browser
			bContinue = true;		res = -1;
			break;
		case 4:		case 5:		case 6:		case 7:
			bContinue = false;		res = -1;
			break;
		case 8:
			bContinue = true;		res = -1;
			break;
		case 1:
			if(Dlg->GetCheck(421)) dUnits = 1;
			else if(Dlg->GetCheck(422)) dUnits = 2;
			else dUnits = 0;
			}
		}while (res < 0);
	if(res == 1) {
		if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE))	DecPoint[0] = TmpTxt[0];
		if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE))	ColSep[0] = TmpTxt[0];
		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
		SetLine(tmpUnits, &LineDef, 0);
		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
		SetLine(tmpUnits, &LineDef, 2);
		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&FillDef, 0);
		SetFill(tmpUnits, &FillDef);
		Dlg->GetInt(301, &dlgtxtheight);
		if(Dlg->GetText(352, date_info, 50) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
			if(defs.fmt_date = (char*)realloc(defs.fmt_date, (cb = (int)strlen(date_info) +2)))
				rlp_strcpy(defs.fmt_date, cb, date_info);
			}
		if(Dlg->GetText(355, datetime_info, 50) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
			if(defs.fmt_datetime = (char*)realloc(defs.fmt_datetime, (cb = (int)strlen(datetime_info) +2)))
				rlp_strcpy(defs.fmt_datetime, cb, datetime_info);
			}
		if(Dlg->GetText(358, time_info, 50) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
			if(defs.fmt_time = (char*)realloc(defs.fmt_time, (cb = (int)strlen(time_info) +2)))
				rlp_strcpy(defs.fmt_time, cb, time_info);
			}
		bRet = true;
		}
	CloseDlgWnd(hDlg);
	delete Dlg;
	return bRet;
}
