#include "dlgedit.h"

char* ctrlClassNames[] =  	{	"GroupBox", "StaticText", "StaticImage", "PushButton",
								"CheckBox", "RadioButton", "Edit", "ScrollBar", "ListBox",
								"ComboBox"	};
int ctrlDefSizes[][2] =		{	{ 100, 100 }, { 80, 18 }, { 50, 50 }, { 80, 30 },
								{ 80, 25 }, { 80, 25 }, { 60, 34 }, { 100, 16 }, { 100, 100 },
								{ 80, 34 } 	};
xmStyle ctrlAllStyles[] = 	{	XmSnone, XmSleft | XmSright | XmScenter, XmSnone, XmSdefault,
								XmSnone, XmSnone, XmSmultiLine, XmShorizontal | XmSvertical, XmSsingleSel | XmSmultipleSel,
								XmSsimple | XmSdropdown | XmSdropdownlist };
xmStyle ctrlDefStyles[] =	{	XmSnone, XmSleft, XmSnone, XmScenter,
								XmSnone, XmSnone, XmSnone, XmShorizontal, XmSsingleSel,
								XmSdropdown };
char* ctrlDefText[] =		{	"Group...", "Text...", "Image", "Push",
								"Check", "Radio", "", "-scroll-", "List",
								"Combo" };
char* ctrlTextPref[] =		{	"(", "", "?", "[",
								"[X] ", "[O] ", "", "", "|| ",
								"|" };
char* ctrlTextPostf[] =		{	")", "", "?", "]",
								"", "", "", "", " ||",
								" |v|" };

char* alignStyleNames[] = 		{	"left", "right", "center", NULL };
xmStyle alignStyleValues[3] = 	{	XmSleft, XmSright, XmScenter };

char* dlgStyleConstants[12] = 	{	"XmSmaximize", "XmSminimize", "XmSbordered", "XmSmoveable",
									"XmSresizeable", "XmScloseable", "XmStitled", "XmSsysMenu",
									"XmSdlgModeless", "XmSdlgWinModal", "XmSdlgAppModal",
									"XmSdlgSysModal" };
xmStyle dlgStyleValues[12] = 	{	XmSmaximize, XmSminimize, XmSbordered, XmSmoveable, XmSresizeable,
									XmScloseable, XmStitled, XmSsysMenu, XmSdlgModeless,
									XmSdlgWinModal, XmSdlgAppModal, XmSdlgSysModal };

char* ctrlStyleConstants[27] = 	{	"XmSleft", "XmSright", "XmScenter", "XmShorizontal", "XmSvertical",
									"XmStop", "XmSbottom", "0", "XmSdefault", "XmStabStop", "XmSautovscroll",
									"XmSautohscroll", "XmSmultiLine", "XmSautoCursor", "XmSsingleSel",
									"XmSmultipleSel", "0", "XmSsimple", "XmSdropdown", "XmSdropdownlist", "0",
									"XmSblackFrame", "XmSgrayFrame", "XmSwhiteFrame", "XmSblackRectangle",
									"XmSgrayRectangle", "XmSwhiteRectangle" };

ReWindow* Editor;

char* tbName[] =		{ "Control name:", "ControlNameEdit", NULL };
char* tbText[] =		{ "Control text:", "ControlTextEdit", NULL };
char* tbNameAndText[] =	{ "Control name:", "ControlNameEdit", "Control text:", "ControlTextEdit", NULL };
char* tbAlignment[] =	{ "Alignment", "Alignments", NULL };
char* tbScroll[] = 		{ "Horizontal Scroll", "Vertical Scroll", NULL };
char* tbCombo[] = 		{ "Simple", "Dropdown", "Dropdownlist", NULL };
char* tbAllStyles[] = 	{ "Alignment", "Alignments", "Tab Stop", "Text and List Styles",
						  "Horizontal Scroll", "Vertical Scroll", "Multiple Lines", "Multiple Selection",
						  "Combo Box Styles", "Simple", "Dropdown", "Dropdownlist", NULL };

// editor I/O stuff... //////////////////////////////////////////////////////

#include "hxdmp.C"

#define RE_EOI "G0"
#define RE_DLG "G1"
#define RE_CTR "G2"
#define RE_NAM "G3"
#define RE_IID "G4"
#define RE_GEO "G5"
#define RE_STY "G6"
#define RE_SUB "G7"
#define RE_DLM "G9"


// app init... //////////////////////////////////////////////////////////////

void XmApp::initialize()
{
	(Editor = new ReWindow)->gnuInit();		// initialize();
};


// impl. ////////////////////////////////////////////////////////////////////

ReDialog::ReDialog(HexDumper& d) : CiObject(new Rectangle(0, 0, 1, 1), "Dialog")
{
	int x, y, w, h, * dims[5];
	x = y = w = h = 0;
	dims[0] = &x; dims[1] = &y; dims[2] = &w; dims[3] = &h; dims[4] = NULL;
	char b[100], bt[100], * n = b, * t = bt;

	if(	d.getMarker(RE_DLG) &&
		d.getComponent(RE_NAM, &n) &&
		d.getComponent(RE_IID, &t) &&
		d.getComponent(RE_GEO, dims) &&
		d.getComponent(RE_STY, &style))
	{	valid = TRUE;
		setDescr(n);
		setContents(t);
		setOrigin(x, y);
		setExtent(w, h);
// cerr << "dlg: " << n << " " << x << "@" << y << "@" << "/" << w << "@" << h << "...\n";
		if(d.getMarker(RE_SUB, 1))
		{	do
			{	ReControl* aControl = new ReControl(d, this);
				if(!(valid = aControl->isValid()))
					break;
			} while(!d.getMarker(RE_EOI, 1));
		}
	}
	else
cerr << "error - dlg: " << n << " " << x << "@" << y << "/" << w << "@" << h << "...\n";
	setCallback(Mark, this, CB(ReDialog::setAsCurrent), TRUE, TRUE);
	setCallback(Activate, this, CB(ReDialog::editConfig));

	allowAssignmentOf("ReControlTemplateClass", "ReControlClass", NULL);

	textHorzAlign(GPR_CENTER);
	textVertAlign(GPR_BEGINNING);
}

ReDialog::ReDialog(int x, int y) : CiObject(new Rectangle(x, y, 300, 200), "Dialog")
{
	valid = TRUE;
	setDescr("Dialog");
	setContents("New Dialog");
	style = 0L;

	setCallback(Mark, this, CB(ReDialog::setAsCurrent), TRUE, TRUE);
	setCallback(Activate, this, CB(ReDialog::editConfig));

	allowAssignmentOf("ReControlTemplateClass", "ReControlClass", NULL);

	textHorzAlign(GPR_CENTER);
	textVertAlign(GPR_BEGINNING);
}

ReDialog::~ReDialog()
{
	// cerr << "dlg " << name << " destr...\n";
}

void ReDialog::setAsCurrent(void*)
{
	Editor->setCurrent(NULL);
}

void ReDialog::editConfig(void*)
{
	Editor->editDlgSettings(NULL);
}

char* ReDialog::dumpOn(HexDumper& d)
{
	int x = origin().x, y = origin().y, w = extent().x, h = extent().y, * dims[5];
	dims[0] = &x; dims[1] = &y; dims[2] = &w; dims[3] = &h; dims[4] = NULL;

	d.putMarker(RE_DLG);
	d.putComponent(RE_NAM, name);
	d.putComponent(RE_IID, text);
	d.putComponent(RE_GEO, dims);
	d.putComponent(RE_STY, style);

	if(child(0))
	{	int i = 0;
		CiObject* aChild;

		d.putMarker(RE_SUB);
		while(aChild = child(i++))
			((ReControl* )aChild)->dumpOn(d);
		d.putMarker(RE_EOI);
	}
	return(NULL);
}

char* ReDialog::dumpOn(ostream& o)
{
	o << "\n/* default class template for: " << name << "\n\n";
	o << "class " << name << " : public XmUserDialog\n{\n";
	o << "#ifndef __GNUG__\n";
	o << "\tbool initWindowSize(int&, int&, int&, int&);\n";
	o << "#endif\n";
	o << "\tvoid createContents();\n\tvoid initContents();\t//should be defined by the application\n";
	o << "public:\n\t" << name << "(char* name = \"" << text << "\"";
	o << ", XmObject* parent = NULL) : XmUserDialog(name, parent, 0x0L";
	for(int i = 0; i < RE_DIALOG_STYLE_COUNT; i++)
	{	if(style & dlgStyleValues[i])
			o << " | " << dlgStyleConstants[i];
	}
	o << ")\n\t{ }\n";
	o << "#ifdef __GNUG__\n";
	o << "\tgnuOpen()\t{ setInitWindowSize(0, 0, " << extent().x << ", " << extent().y << "); ";
	o << name << "::createContents(); " << name << "::initContents(); realize(); }\n";
	o << "#endif\n";
	o << "\n\t// application functions...\n};\n\n*/";
	o << "\n\n#ifndef __GNUG__\n";
	o << "bool " << name << "::initWindowSize(int&, int&, int& w, int& h)\n{\n";
	o << "\tw = " << extent().x << ";\n\th = " << extent().y << ";\n\treturn(TRUE);\n}\n";
	o << "#endif\n";
	o << "\nvoid " << name << "::createContents()\n{";
	if(child(0))
	{	int i = 0;
		ReControl* aChild;

		while(aChild = (ReControl* )child(i++))
		{	if(aChild->isCtrl(GroupBox))
			{	o << "\n\tXmGroupBox* groups[10];\n\tint groupCount = 0;\n";
				break;
			}
		}
		i = 0;
		while(aChild = (ReControl* )child(i++))
			aChild->dumpOn(o);
	}
	o << "\n}\n\n";
	return(NULL);
}

ReControl::ReControl(HexDumper& d, CiObject* par) : CiObject(new Rectangle(0, 0, 1, 1), "Control")
{
	int x, y, w, h, * dims[5];
	x = y = w = h = 0;
	dims[0] = &x; dims[1] = &y; dims[2] = &w; dims[3] = &h; dims[4] = NULL;
	unsigned long cls;
	char bn[100], bt[100];
	char* n = bn, * t = bt;

	if(	d.getComponent(RE_CTR, &cls) &&
		d.getComponent(RE_NAM, &n) &&
		d.getComponent(RE_IID, &t) &&
		d.getComponent(RE_GEO, dims) &&
		d.getComponent(RE_STY, &style))
	{	valid = TRUE;
		ctrlClass = (ctrlType )cls; 
		setDescr(n);
		setContents(t);
		changeName(ctrlClassNames[ctrlClass]);
		setInitialOrigin(x, y);
		setExtent(w, h);
		par->addChild(this);
// cerr << "   ctrl: " << n << "/" << par->className() << " " << x << "@" << y << "@" << "/" << w << "@" << h << "...\n";
		if(d.getMarker(RE_SUB, 1))
		{	do
			{	ReControl* aControl = new ReControl(d, this);
				if(!(valid = aControl->isValid()))
					break;
			} while(!d.getMarker(RE_EOI, 1));
		}
	}
	else
cerr << "   error - ctrl: " << n << "(" << t << ") " << x << "@" << y << "/" << w << "@" << h << "...\n";
	setCallback(Mark, this, CB(ReControl::setAsCurrent), TRUE, TRUE);

	if(ctrlClass == GroupBox)
		allowAssignmentOf("ReControlTemplateClass", "ReControlClass", NULL);
	allowAssigningTo("Dialog", "GroupBox", NULL);

	textHorzAlign((style & XmScenter || ctrlClass == PushButton) ? GPR_CENTER : (style & XmSright ? GPR_END : GPR_BEGINNING));
	textVertAlign(ctrlClass == GroupBox ? GPR_BEGINNING : GPR_CENTER);
}

ReControl::ReControl(ReControlTemplate* t) : CiObject(new Rectangle(t->relOrigin().x, t->relOrigin().y, ctrlDefSizes[t->getClass()][0], ctrlDefSizes[t->getClass()][1]), t->getName())
{
	valid = TRUE;
	ctrlClass = t->getClass();
	style = t->getStyle();
	setDescr(t->getDescr());
	setContents(t->getContents());

	setCallback(Mark, this, CB(ReControl::setAsCurrent), TRUE, TRUE);

	// if(style == GroupBox) ??????
	if(ctrlClass == GroupBox)
		allowAssignmentOf("ReControlTemplateClass", "ReControlClass", NULL);
	allowAssigningTo("Dialog", "GroupBox", NULL);

	textHorzAlign(style & XmScenter ? GPR_CENTER : GPR_BEGINNING);
	textVertAlign(ctrlClass == GroupBox ? GPR_BEGINNING : GPR_CENTER);
}

ReControl::ReControl(ctrlType t, int x, int y) : CiObject(new Rectangle(x, y, ctrlDefSizes[t][0], ctrlDefSizes[t][1]), ctrlClassNames[t])
{
	valid = TRUE;
	ctrlClass = t;
	style = ctrlDefStyles[t];
	setDescr(ctrlClassNames[t]);
	setContents(ctrlDefText[t]);

	setCallback(Mark, this, CB(ReControl::setAsCurrent), TRUE, TRUE);

	allowAssigningTo("Dialog", "GroupBox", "WORLD", NULL);
}

ReControl::~ReControl()
{
}

void ReControl::setAsCurrent(void*)
{
	Editor->setCurrent(isTemplate() ? NULL : this);
}

char* ReControl::getGrpEdDescr()
{
static char outbuf[100];
	ostrstream out(outbuf, 100);

	out << name << " / \"" << text << "\"";
	out.put('\0');
	return(out.str());
}

ReControl* ReControl::deepCopy()
{
	ReControl* aChild, * aCtr = new ReControl((ReControlTemplate* )this);
	int i = 0;

	aCtr->setOrigin(origin().x, origin().y);
	aCtr->setExtent(extent().x, extent().y);

	while(aChild = (ReControl* )child(i++))
		aCtr->addChild(aChild->deepCopy());
	return(aCtr);
}

char* ReControl::dumpOn(HexDumper& d)
{
	int x = relOrigin().x, y = relOrigin().y, w = extent().x, h = extent().y, * dims[5];
	dims[0] = &x; dims[1] = &y; dims[2] = &w; dims[3] = &h; dims[4] = NULL;
	unsigned long cls = getClass();

	d.putComponent(RE_CTR, cls);
	d.putComponent(RE_NAM, name);
	d.putComponent(RE_IID, text);
	d.putComponent(RE_GEO, dims);
	d.putComponent(RE_STY, style);

	if(child(0))
	{	int i = 0;
		CiObject* aChild;

		d.putMarker(RE_SUB);
		while(aChild = child(i++))
			((ReControl* )aChild)->dumpOn(d);
		d.putMarker(RE_EOI);
	}
	return(NULL);
}

char* ReControl::dumpOn(ostream& o)
{
	o << "\n\t";
	if(((ReControl *)getParent())->isCtrl(GroupBox))
		o << "groups[groupCount]->";
	o << "add((";
	if(isCtrl(GroupBox))
		o << "groups[++groupCount] = ";
	o << "new Xm" << ctrlClassNames[ctrlClass] << "(\"" << name << "\", " << relOrigin().x << ", " << relOrigin().y;
	o << ", " << extent().x << ", " << extent().y << ", 0x0";
	for(int i = 0; i < RE_CONTROL_STYLE_COUNT; i++)
	{	if(style & (1 << i))
			o << " | " << ctrlStyleConstants[i];
	}
	o << "))";
	if(	isCtrl(GroupBox) || isCtrl(StaticText) || isCtrl(PushButton) ||
		isCtrl(CheckBox) || isCtrl(RadioButton) )
		o << "->setText(\"" << getContents() << "\")";
	o << ");";
	if(child(0))
	{	int i = 0;
		ReControl* aChild;

		while(aChild = (ReControl* )child(i++))
			aChild->dumpOn(o);
	}
	if(isCtrl(GroupBox))
		o << " groupCount--;";
	return(NULL);
}

ReControlTemplate::ReControlTemplate(ctrlType t, int x, int y)	: ReControl(t, x, y)
{
	fixedLoc.x = x;
	fixedLoc.y = y;
	setCallback(Assign, this, CB(ReControlTemplate::makeInstance)); //, TRUE, FALSE, CB_CI_DATA);
	setText(ctrlClassNames[t]);
}

ReControlTemplate::~ReControlTemplate()
{
}

void ReControlTemplate::makeInstance(void*)
{
	if(getParent())
	{	getWorld()->refresh();
		getParent()->addChild(new ReControl(this));
		assign(NULL, fixedLoc.x, fixedLoc.y);
	}
}

// the application window //////////////////////////////////////////////////

bool ReWorld::userSelect(DrawPrim* p, int, int)
{
	if(!p)
	{	Editor->setCurrent(NULL);
		return(TRUE);
	}
	return(XmCiWorld::userSelect(p, 0, 0));
}

ReWindow::ReWindow() : XmWindow("Dialog Editor")
{
	clipboard = NULL;
}

void ReWindow::initialize()
{
	XmDropdownMenu* m = createDropdownMenu();

	m->addLabel("&File");
	m->addLabel("&Edit");
	m->addLabel("&Misc");
	m->setCurrentLabel("File");
	m->addItem(Entry("&Open...", (XmObject* )NULL, (cbProc )&ReWindow::fcmdOpen));
	m->addItem(Entry("&New", (XmObject* )NULL, (cbProc )&ReWindow::fcmdNew));
	m->addItem(Entry("&Save", (XmObject* )NULL, (cbProc )&ReWindow::fcmdSave));
	m->addItem(Entry("Save &As...", (XmObject* )NULL, (cbProc )&ReWindow::fcmdSave));
	m->addSeparator();
	m->addItem(Entry("E&xit", (XmObject* )NULL, (cbProc )&ReWindow::quit));
	m->setCurrentLabel("Edit");
	m->addItem(Entry("&Cut", (XmObject* )NULL, (cbProc )&ReWindow::ecmd));
	m->addItem(Entry("C&opy", (XmObject* )NULL, (cbProc )&ReWindow::ecmd));
	m->addItem(Entry("&Paste", (XmObject* )NULL, (cbProc )&ReWindow::ecmd));
	m->addSeparator();
	m->addItem(Entry("&Delete", (XmObject* )NULL, (cbProc )&ReWindow::ecmd));
	m->setCurrentLabel("Misc");
	m->addItem(Entry("&Test...", (XmObject* )NULL, (cbProc )&ReWindow::openTest));
	m->addItem(Entry("&Order/Groups...", (XmObject* )NULL, (cbProc )&ReWindow::editGroups));
	m->addItem(Entry("&Dialog Settings...", (XmObject* )NULL, (cbProc )&ReWindow::editDlgSettings));
	m->addItem(Entry("Set &Grid...", (XmObject* )NULL, (cbProc )&ReWindow::mcmd));
	m->addSeparator();
	m->addItem(Entry("&About...", (XmObject* )NULL, (cbProc )&ReWindow::about));

	curEdited = NULL;
	currFileName = NULL;
	curSelected = NULL;
	curTested = NULL;
	curGroupEditor = NULL;

	addSubpane(world = new ReWorld("Dialog Edit"));
	createCiWorld();
	createStylesBar();
	createNamesBar();
	toolbar(XmStop)->disableAll(tbNameAndText);
	toolbar(XmSright)->disableAll(tbAllStyles);
}

void ReWindow::createNamesBar()
{
	XmToolBar* tb;

	tb = addToolbar(XmStop);
	tb->add((new XmStaticText("Control name:")));
	tb->add((new XmEdit("ControlNameEdit")), this, CB(ReWindow::changeName));
	tb->add((new XmStaticText("Control text:")));
	tb->add((new XmEdit("ControlTextEdit")), this, CB(ReWindow::changeText));
}

void ReWindow::createStylesBar()
{
	XmToolBar* tb;

	tb = addToolbar(XmSright);
	tb->add((new XmStaticText("Alignment")));
	tb->add((XmGroupBox* )(new XmComboBox("Alignments", 0, 0, 150, 150, XmSdropdownlist)), this, CB(ReWindow::changeAlignment));
	tb->add((new XmCheckBox("&Tab Stop")), this, CB(ReWindow::changeStyle));
	tb->add((new XmStaticText("Text and List Styles")));
	tb->add((new XmCheckBox("&Horizontal Scroll")), this, CB(ReWindow::changeStyle));
	tb->add((new XmCheckBox("&Vertical Scroll")), this, CB(ReWindow::changeStyle));
	tb->add((new XmCheckBox("Multiple &Lines")), this, CB(ReWindow::changeStyle));
	tb->add((new XmCheckBox("Multiple &Selection")), this, CB(ReWindow::changeStyle));
	tb->add((new XmStaticText("Combo Box Styles")));
	tb->add((new XmRadioButton("Si&mple")), this, CB(ReWindow::changeComboStyle));
	tb->add((new XmRadioButton("&Dropdown")), this, CB(ReWindow::changeComboStyle));
	tb->add((new XmRadioButton("Dropdown&list")), this, CB(ReWindow::changeComboStyle));
}

void ReWindow::fcmdNew(void* ptr)
{
	if(pendingChanges)
	{	if((new XmMsgBox("Abort pending changes ?", "File changed!", XmSmboxQuestion))->showMsg())
			pendingChanges = FALSE;
	}
	if(!pendingChanges)
	{	delete curEdited;
		delete currFileName;
		currFileName = NULL;
		if(ptr)
			world->addChild(curEdited = new ReDialog(200, 30));
		else
			curEdited = NULL;
		world->refresh();
	}
}

void ReWindow::fcmdOpen(void*)
{
	char* filename;

	fcmdNew(NULL);
	if(!pendingChanges && (filename = (new XmFileSelector("./*dlg.C"))->promptFile()))
	{	ifstream in(filename);
		char* loadErr = NULL;

		if(in.good())
		{	currFileName = strcpy(new char[strlen(filename) + 1], filename);
			HexDumper dmp(in);
			char buf[100];
			while((in >> buf).good() && strcmp(buf, "@data:"));
			if(in.good())
			{	if((curEdited = new ReDialog(dmp))->isValid())
				{	world->addChild(curEdited);
					world->refresh();
				}
				else
				{	delete curEdited;
					curEdited = NULL;
					loadErr = "Error in binary dialog description.\n";
				}
			}
			else
				loadErr = "Invalid input file.\n";
		}
		else
			loadErr = "Error opening input file.\n";
		in.close();
		if(loadErr)
		{	cerr << loadErr << "\n";
			delete currFileName;
			currFileName = NULL;
		}
	}
	if(!curEdited)
		world->addChild(curEdited = new ReDialog(200, 30));
}

#define RE_FILE_HEADER "Hello, this is Re 0.001..."

void ReWindow::fcmdSave(char* cmd)
{
	char* filename = currFileName;

	if(!filename || strcmp(cmd, "Save"))
	{	ostrstream defname;
		if(!filename)
		{	defname << curEdited->getDescr() << "dlg.C";
			filename = defname.str();
		}
		filename = (new XmFileSelector("./*dlg.C", filename))->promptFile();
		// check for overwriting here...
	}

	if(filename)
	{	ofstream out(filename);
		HexDumper dmp(out);
		char* saveErr = NULL;

		out << "/*" << RE_FILE_HEADER << "\n\t" << curEdited->getDescr() << "\n\n @data:\n";
		if(!(saveErr = curEdited->dumpOn(dmp)))
		{	out << "\n\n*/\n\n";
			saveErr = curEdited->dumpOn(out);
		}
		out.close();
		if(saveErr)
		{	cerr << saveErr << "\n";
			currFileName = NULL;
		}
		else
		{	pendingChanges = FALSE;
			currFileName = filename;
		}
	}
}

/*
void ReWindow::ecmd(char* cmd)
{
	if(curSelected)
	{	ReControl* aCtrl = curSelected;
		if(*cmd == 'D' && aCtrl)
		{	setCurrent(NULL);
			world->clearSelections();
			delete aCtrl;
		}
	}
}
*/

void ReWindow::ecmd(char* cmd)
{
	int i = 0;

	if(curSelected && *cmd != 'P')
	{	ReControl** ctrls = (ReControl** )curEdited->getChildren(CH_SHALLOW, MARKED);
		if(*cmd == 'D' && ctrls[0])
		{	setCurrent(NULL);
			world->clearSelections();
			while(ctrls[i])
				delete ctrls[i++];
			delete ctrls;
		}
		else if(*cmd == 'C')
		{	if(clipboard)
			{	while(clipboard[i])
					delete clipboard[i++];
				delete clipboard;
			}
			if(cmd[1] == 'u')
			{	clipboard = ctrls;
				i = 0;
				world->clearSelections();
				while(ctrls[i])
					ctrls[i++]->unlink();
				world->refresh();
			}
			else
			{	clipboard = new ReControl*[100];
				i = 0;
				while(ctrls[i])
				{	clipboard[i] = ctrls[i]->deepCopy();
					i++;
				}
				clipboard[i] = NULL;
				delete ctrls;
			}
		}
	}
	if(*cmd == 'P' && clipboard)
	{	world->clearSelections();
		while(clipboard[i])
			clipboard[i++]->deepCopy()->linkTo(world);
		world->refresh();
	}
}

void ReWindow::mcmd(char* cmd)
{
	if(*cmd == 'S')
	{	char* newGrid;
		ostrstream out;
		out << world->getGrid(); out.put('\0');
		if(newGrid = (new XmPrompter("Enter new value:", "Layout Grid", out.str()))->prompt())
		{	istrstream in(newGrid, strlen(newGrid));
			int val;
			in >> val;
// cerr << "setting grid to " << val << "\n";
			world->setGrid(val);
		}
	}
}

void ReWindow::openTest(void*)
{
// cerr << "open test...\n";
	(curTested = new ReTestDlg(curEdited))->gnuOpen();	// open();
}

void ReWindow::editGroups(void*)
{
// cerr << "edit groups...\n";
	(curGroupEditor = new ReGroupConfig(curEdited))->gnuOpen();	// open();
}

void ReWindow::editDlgSettings(void*)
{
// cerr << "edit dlg settings...\n";
	(new ReDialogConfig(curEdited, this))->gnuOpen();	// open();
}

void ReWindow::about(void*)
{
}


void ReWindow::quit(void*)
{
	exit(0);
}


void ReWindow::createCiWorld()
{
	world->setGrid(6);
	world->addChild(curEdited = new ReDialog(200, 30));

	int ny = 30;

	for(int i = 0; i < MAX_RE_CONTROLS; i++)
	{	world->addChild(new ReControlTemplate((ctrlType )i, 10, ny));
		ny += ctrlDefSizes[i][1] + 10;
	}
}

void ReWindow::changeName(XmEdit*)
{
}

void ReWindow::changeText(XmEdit*)
{
}

void ReWindow::changeAlignment(XmComboBox*)
{
}

void ReWindow::changeStyle(XmCheckBox*)
{
}

void ReWindow::changeComboStyle(XmRadioButton*)
{
}


void ReWindow::setCurrent(ReControl* aContr)
{
	bool set = aContr ? (aContr->getState(MARKED) ? FALSE : TRUE) : FALSE;
	bool reset = (set == FALSE || (curSelected != NULL && curSelected != aContr)) ? TRUE : FALSE;
	ctrlType aClass;
	XmToolBar* tb;

// cerr << "setCurrent..." << (aContr ? aContr->getDescr() : "NULL") << " - " << set << reset << "\n";
// cerr << "setCurrent..." << (XmProcessTraversal(tb->handle(), XmTRAVERSE_CURRENT) ? "OK" : "SHIT!") << "?\n";

	if(reset)
	{	if(curSelected)
		{	aClass = curSelected->getClass();
			tb = toolbar(XmStop);
			curSelected->setDescr((tb->edit("ControlNameEdit"))->getText());
			curSelected->setContents(tb->edit("ControlTextEdit")->getText());
			tb->edit("ControlNameEdit")->setText("");
			tb->edit("ControlTextEdit")->setText("");

			tb = toolbar(XmSright);
			xmStyle newStyle = 0;
			if(aClass == StaticText)
			{	newStyle |= alignStyleValues[tb->comboBox("Alignments")->selectedIndex() - 1];
				tb->comboBox("Alignments")->setText("");
				tb->comboBox("Alignments")->clear();
			}
			if(tb->checkBox("Tab Stop")->getState())
			{	newStyle |= XmStabStop;
				tb->checkBox("Tab Stop")->setState(FALSE);
			}
			if((aClass == Edit || aClass == ListBox) && tb->checkBox("Horizontal Scroll")->getState())
			{	newStyle |= XmSautohscroll;
				tb->checkBox("Horizontal Scroll")->setState(FALSE);
			}
			if((aClass == Edit || aClass == ListBox) && tb->checkBox("Vertical Scroll")->getState())
			{	newStyle |= XmSautovscroll;
				tb->checkBox("Vertical Scroll")->setState(FALSE);
			}
			if(aClass == Edit && tb->checkBox("Multiple Lines")->getState())
			{	newStyle |= XmSmultiLine;
				tb->checkBox("Multiple Lines")->setState(FALSE);
			}
			if(aClass == ListBox && tb->checkBox("Multiple Selection")->getState())
			{	newStyle |= XmSmultipleSel;
				tb->checkBox("Multiple Selection")->setState(FALSE);
			}
			if(aClass == ComboBox)
			{	if(tb->radioButton("Simple")->getState())
				{	newStyle |= XmSsimple;
					tb->radioButton("Simple")->setState(FALSE);
				}
				if(tb->radioButton("Dropdown")->getState())
				{	newStyle |= XmSdropdown;
					tb->radioButton("Dropdown")->setState(FALSE);
				}
				if(tb->radioButton("Dropdownlist")->getState())
				{	newStyle |= XmSdropdownlist;
					tb->radioButton("Dropdownlist")->setState(FALSE);
				}
			}
			curSelected->setStyle(newStyle);
			curSelected = NULL;
		}
		toolbar(XmSright)->disableAll(tbAllStyles);
		if(!set)
			toolbar(XmStop)->disableAll(tbNameAndText);
	}
	if(set)
	{	aClass = aContr->getClass();
		tb = toolbar(XmStop);
		if(!reset)
			tb->enableAll(tbNameAndText);
		curSelected = aContr;
		tb->edit("ControlNameEdit")->setText(aContr->getDescr());
		tb->edit("ControlTextEdit")->setText(aContr->getContents());

		tb = toolbar(XmSright);
		xmStyle oldStyle = aContr->getStyle();
		if(aClass == StaticText)
		{	int ndx = (oldStyle & XmSleft ? 0 : (oldStyle & XmSright ? 1 : 2));
			tb->comboBox("Alignments")->enable();
			tb->comboBox("Alignments")->addAll(alignStyleNames);
			tb->comboBox("Alignments")->selectIndex(ndx + 1, TRUE);
//			tb->comboBox("Alignments")->setText(alignStyleNames[ndx]);
		}
		tb->checkBox("Tab Stop")->enable();
		if(oldStyle & XmStabStop)
				tb->checkBox("Tab Stop")->setState(TRUE);
		if(aClass == Edit || aClass == ListBox)
		{	tb->checkBox("Horizontal Scroll")->enable();
			if(oldStyle & XmSautohscroll)
				tb->checkBox("Horizontal Scroll")->setState(TRUE);
			tb->checkBox("Vertical Scroll")->enable();
			if(oldStyle & XmSautovscroll)
				tb->checkBox("Vertical Scroll")->setState(TRUE);
		}
		if(aClass == Edit)
		{	tb->checkBox("Multiple Lines")->enable();
			if(oldStyle & XmSmultiLine)
				tb->checkBox("Multiple Lines")->setState(TRUE);
		}
		if(aClass == ListBox && tb->checkBox("Multiple Selection")->getState())
		{	tb->checkBox("Multiple Selection")->enable();
			if(oldStyle & XmSmultipleSel)
				tb->checkBox("Multiple Selection")->setState(TRUE);
		}
		if(aClass == ComboBox)
		{	tb->enableAll(tbCombo);
			if(oldStyle & XmSsimple)
				tb->radioButton("Simple")->setState(TRUE);
			if(oldStyle & XmSdropdown)
				tb->radioButton("Dropdown")->setState(TRUE);
			if(oldStyle & XmSdropdownlist)
				tb->radioButton("Dropdownlist")->setState(TRUE);
		}
	}
	pendingChanges = TRUE;		// let's assume that the user has altered something....
}

// the dialog config dialog... //////////////////////////////////////////////

#include "redlg.C"

char* chkbxs[] = { "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", NULL };
char* rdbuts[] = { "dm1", "dm2", "dm3", "dm4", NULL };

void ReDialogConfig::initContents()
{
	pushButton("pbOk")->setCallback(this, CB(ReDialogConfig::cmd), TRUE, CB_OBJ_NAME);
	pushButton("pbCancel")->setCallback(this, CB(ReDialogConfig::cmd), TRUE, CB_OBJ_NAME);
	pushButton("pbHelp")->disable();
	edit("dlgName")->setText(theDlg->getDescr());
	edit("dlgLabel")->setText(theDlg->getContents());
	char* aName;
	int i;
	for(i = 0; aName = chkbxs[i]; i++)
		checkBox(aName)->setState((theDlg->getStyle() & (1 << i)) ? TRUE : FALSE);
	for(i = 0; aName = rdbuts[i]; i++)
	{	if(theDlg->getStyle() & (1 << (15 + i)))
		{	radioButton(aName)->setState(TRUE);
			break;
		}
	}
	destroyOnDelete();
}

void ReDialogConfig::cmd(char* aStr)
{
	if(!strcmp(aStr, "pbOk"))
	{	theDlg->setDescr(edit("dlgName")->getText());
		theDlg->setContents(edit("dlgLabel")->getText());

		xmStyle aStyle = 0L;
		char* aName;
		int i;
		for(i = 0; aName = chkbxs[i]; i++)
		{	if(checkBox(aName)->getState())
				aStyle |= (1 << i);
		}
		for(i = 0; aName = rdbuts[i]; i++)
		{	if(radioButton(aName)->getState())
			{	aStyle |= (1 << (15 + i));
				break;
			}
		}
		theDlg->setStyle(aStyle);
	}
	delete this;
}

// the control order stuff //////////////////////////////////////////////////

#define RE_GRI_WIDTH 220
#define RE_GRI_HEIGHT 20
#define RE_GRI_SPACING 8

ReGroupItem::ReGroupItem(ReControl* aCtr, int ndx, int x, int y) : CiObject(new Rectangle(x, y, RE_GRI_WIDTH, RE_GRI_HEIGHT), aCtr->getGrpEdDescr())
{
	theControl = aCtr;
	tmpIndex = ndx;
	setText(aCtr->getGrpEdDescr());
}

void ReGroupItem::moved(void*)
{
	// cerr << "item moved...\n";
}

bool ReGroupWorld::userMove(DrawPrim* p, int x, int y, int x0, int y0)
{
	if(!p)
	{	ReGroupItem* anItem, *startItem = NULL, * moved[200], * notMoved[200], * ordered[200];
		int ndx, i = 0, movedCount = 0, notMovedCount = 0, orderedCount = 0;

		ndx = y / (RE_GRI_HEIGHT + RE_GRI_SPACING);
// cerr << "ordering, target ndx " << ndx << "...\n";
		while(anItem = (ReGroupItem* )child(i++))
		{	if(anItem->wasMoved())
				moved[movedCount++] = anItem;
			else
			{	if(i <= ndx)
					startItem = anItem;
				notMoved[notMovedCount++] = anItem;
			}
		}
/*
cerr << "moved " << movedCount << " - not moved " << notMovedCount << ", starting after "
 << (startItem ? startItem->theControl->getDescr() : "LAST") << "\n";
*/
		int j = 0, k = 0;
		if(startItem)
		{	do
				ordered[orderedCount++] = anItem = notMoved[j++];
			while(anItem != startItem);
		}
		while(k < movedCount)
			ordered[orderedCount++] = moved[k++];
		while(j < notMovedCount)
			ordered[orderedCount++] = notMoved[j++];
// cerr << "new order: \n";
		for(i = 0; i < orderedCount; i++)
		{	ordered[i]->tmpIndex = i;
			// cerr << ordered[i]->theControl->getDescr() << "\n";
		}
		XmCiWorld::userMove(p, x, y, x0, y0);
		master->reArrange(FALSE);
	}
	else
		return(XmCiWorld::userMove(p, x, y, x0, y0));
	return(TRUE);
}

ReGroupConfig::ReGroupConfig(ReDialog* aDlg) : XmWindow("Control Order", Editor)
{
	theDlg = aDlg;
}

void ReGroupConfig::initialize()
{
	XmToolBar* tb;

	tb = addToolbar(XmSright);
	tb->add((new XmPushButton("OK")), this, CB(ReGroupConfig::cmd), CB_OBJ_NAME);
	tb->add((new XmPushButton("Cancel")), this, CB(ReGroupConfig::cmd), CB_OBJ_NAME);

	addSubpane(world = new ReGroupWorld(this));
	reArrange(TRUE);

	destroyOnDelete();
}

void ReGroupConfig::addGroup(ReControl* aGrp, int& ndx)
{
	int i = 0;
	ReControl* aCtr;

	while(aCtr = (ReControl* )aGrp->child(i++))
	{	world->addChild(new ReGroupItem(aCtr, ndx, 5, RE_GRI_SPACING + ndx++ * (RE_GRI_HEIGHT + RE_GRI_SPACING)));
		if(aCtr->isCtrl(GroupBox))
			addGroup(aCtr, ndx);
	}
}

void ReGroupConfig::reArrange(bool firstTime)
{
	int ndx = 0, i = 0;

	if(firstTime)
	{	ReControl* aCtr;

		while(aCtr = (ReControl* )theDlg->child(i++))
		{	world->addChild(new ReGroupItem(aCtr, ndx, 5, RE_GRI_SPACING + ndx++ * (RE_GRI_HEIGHT + RE_GRI_SPACING)));
			if(aCtr->isCtrl(GroupBox))
				addGroup(aCtr, ndx);
		}
	}
	else
	{	ReGroupItem* anItem;
		int ndx = 0, i = 0;

		while(ndx < world->childrenCount())
		{	i = 0;
			while(anItem = (ReGroupItem* )world->child(i++))
			{	if(anItem->tmpIndex == ndx)
				{	anItem->toBackground();
					ndx++;
					break;
				}
			}
		}
		i = 0;
		while(anItem = (ReGroupItem* )world->child(i++))
			anItem->move(5, RE_GRI_SPACING + anItem->tmpIndex * (RE_GRI_HEIGHT + RE_GRI_SPACING));
	}
	world->refresh();
}

void ReGroupConfig::getGroup(ReControl* aGrp)
{
	ReGroupItem* anItem;
	int i = 0;

	while(anItem = (ReGroupItem* )world->child(i++))
	{	ReControl* aCtrl = anItem->theControl;
		if(!aCtrl || aCtrl->getParent() != aGrp)
			continue;
		if(aCtrl->isCtrl(GroupBox))
			getGroup(aCtrl);
		aCtrl->toBackground();
	}
}

void ReGroupConfig::cmd(char* cmd)
{
	if(!strcmp(cmd, "OK"))
	{	ReGroupItem* anItem;
		int i = 0;

		while(anItem = (ReGroupItem* )world->child(i++))
		{	ReControl* aCtrl = anItem->theControl;
			if(!aCtrl)
				continue;
			if(aCtrl->isCtrl(GroupBox))
				getGroup(aCtrl);
			aCtrl->toBackground();
		}
		theDlg->toBackground();
	}
	delete this;
}
		
// the test dialog implementation ///////////////////////////////////////////

/*

bool ReTestDlg::initWindowSize(int&, int&, int& w, int& h)
{
	w = templ->extent().x;
	h = templ->extent().y;
	return(TRUE);
}

*/

void ReTestDlg::createContents()
{
// cerr << "create contents...\n";
	createSubtree(templ, this);
}

char* dummyList[] = { 	"Line 1", "Line 2", "Line 3", "Line 4", "Line 5", "Line 6", "Line 7",
						"Line 8", "Line 9", "Line 10", "Line 11", "Line 12", "Line 13", "Line 14",
						"Line 15", NULL };

void ReTestDlg::createSubtree(CiObject* root, XmDialogPane* par)
{
// cerr << "create subtree...\n";
	int i = 0;
	ReControl* aContr;

	while(aContr = (ReControl* )root->child(i++))
	{	XmControl* xmContr;
		char* n = aContr->getDescr();
		char* t = aContr->getContents();
		int x = aContr->relOrigin().x, y = aContr->relOrigin().y;
		int w = aContr->extent().x, h = aContr->extent().y;
		xmStyle s = aContr->getStyle();

		switch(aContr->getClass())
		{	case StaticText: xmContr = (new XmStaticText(n, x, y, w, h, s))->setText(t); break;
			case StaticImage: xmContr = new XmStaticImage(n, x, y, w, h, s); break;
			case PushButton: xmContr = (new XmPushButton(n, x, y, w, h, s))->setText(t); break;
			case RadioButton: xmContr = (new XmRadioButton(n, x, y, w, h, s))->setText(t); break;
			case CheckBox: xmContr = (new XmCheckBox(n, x, y, w, h, s))->setText(t); break;
			case Edit: xmContr = new XmEdit(n, x, y, w, h, s); break;
			case ListBox: xmContr = new XmListBox(n, x, y, w, h, s); break;
			case ComboBox: xmContr = (XmGroupBox* )new XmComboBox(n, x, y, w, (s & XmSsimple) ? h : 200, s); break;
			case GroupBox: xmContr = (new XmGroupBox(n, x, y, w, h, s))->setText(t); break;
			default: xmContr = (new XmStaticText(n, x, y, w, h, s))->setText("??????"); break;
		}
		par->add(xmContr);
		if(xmContr->isA(GroupBox))
			createSubtree(aContr, (XmGroupBox* )xmContr->getBase());
		else if(xmContr->isA(ListBox))
			((XmListBox* )xmContr)->addAll(dummyList);
		else if(xmContr->isA(ComboBox))
			((XmComboBox* )((XmGroupBox* )xmContr))->addAll(dummyList);
	}
}

