#include <stream.h>

extern "C" { void exit(int); }

#define GPR_DEFAULT_FILL GPR_SOLID

#include "xmCi2.h"


class TestWindow : public XmDialogWindow
{
	XmCiWorld* world;

	void createCiWorld();
public:
	TestWindow();

	void myMenuItem(char*);
	void open(void*);
	void close(void*);

	void moveCiObj(CiObject*);
	void assignCiObj(CiObject*);
	void changeCiObj(ciClientData*);

	void quit(void*);
};

void XmApp::initialize()
{
	new TestWindow;
};


TestWindow::TestWindow() : XmDialogWindow("Test")
{
	setInitWindowSize(300, 300, 400, 600); 

	XmDropdownMenu* m = createDropdownMenu();

	m->addLabel("&File");
	m->addLabel("&Edit");
	m->addLabel("&Misc");
	m->setCurrentLabel("File");
	m->addItem(Entry("&Open", (XmObject* )NULL, (cbProc )&TestWindow::open));
	m->addItem(Entry("&Close", (XmObject* )NULL, (cbProc )&TestWindow::close));
	m->addSeparator();
	m->addItem(Entry("E&xit", (XmObject* )NULL, (cbProc )&TestWindow::quit));

	createCiWorld();
}

void TestWindow::open(void*)
{
	(new TestWindow)->realize();
}

void TestWindow::close(void*)
{
	destroyOnDelete();
	delete this;
}

/*
   Die CI callbacks werden in diesem Fall vom WORLD Window bearbeitet,
   koennen aber genausogut fuer andere (Xm- oder CI- )Objekte definiert
   werden.
*/

void TestWindow::moveCiObj(CiObject* anObj)
{
	cerr << "CiTest: object " << anObj->getName()
		<< " moved inside " << anObj->getParent()->getName() << "\n";
}

void TestWindow::assignCiObj(CiObject* anObj)
{
	cerr << "CiTest: object " << anObj->getName()
		<< " assigned to " << (anObj->getParent() ?
		anObj->getParent()->getName() : "WORLD") << "\n";
}

void TestWindow::changeCiObj(ciClientData* d)
{
	CiObject* anObj = d->clientObject();

	cerr << "CiTest: object " << anObj->getName()
		<< (d->operation == OP_REMOVE ? " looses " : " gets new ")
		<< "child " << d->obj->getName() << "\n";
}


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

/*
   Und hier wird die Welt (eine spezielle Xm++ control Klasse) und ihre
   CI Objekte erzeugt. Im constructor fuer ein CiObject wird hier nur ein
   Graphikobjekt uebergeben, spaeter kann es auch ein Xm++ control sein.
*/

void TestWindow::createCiWorld()
{
	CiObject* anObj, * it;

	add(world = new XmCiWorld("World", 10, 10, 400, 400));

	anObj = new CiObject(new Rectangle(150, 30, 120, 100), "Parent1");
	anObj->setText("Parent1");
	anObj->allowAssignmentOf("Child*", NULL);
	anObj->allowAssigningTo("Parent*", NULL);
	anObj->allowAssigningTo("WORLD", NULL);
	anObj->setCallback(Assign, this, CB(TestWindow::assignCiObj));
	anObj->setCallback(ChangeContents, this, CB(TestWindow::changeCiObj),
						TRUE, FALSE, CB_CI_DATA);

	anObj->addChild(it = new CiObject(new Circle(10, 10, 50), "Child1"));
	it->setText("Child1");
	it->allowAssigningTo("Parent*", NULL);
	it->setCallback(Assign, this, CB(TestWindow::assignCiObj));

	anObj->addChild(it = new CiObject(new Circle(50, 30, 40), "Child2"));
	it->setText("Child2");

	world->addChild(anObj);

	anObj = new CiObject(new Rectangle(10, 200, 100, 80), "Parent2");
	anObj->setText("Parent2");
	anObj->allowAssignmentOf("*", NULL);
	anObj->setCallback(ChangeContents, this, CB(TestWindow::changeCiObj),
						TRUE, FALSE, CB_CI_DATA);

	world->addChild(anObj);
}

/*
   Alles weitere macht CI, nachdem in den callbacks nichts Wesentliches
   passiert. In einer 'echten' App koennen dann in den (CI- und Xm++-)
   callbacks neue CiObjects erzeugt, vorhandene geaendert usw. werden
   (im naechsten example mehr...).
*/
