/////////////////////////////////////////////////////////////
// CINEMA SDK : MENU PLUGINS															 //
/////////////////////////////////////////////////////////////
// VERSION    : CINEMA 4D																	 //
/////////////////////////////////////////////////////////////
// (c) 1989-2002 MAXON Computer GmbH, all rights reserved	 //
/////////////////////////////////////////////////////////////

// example code for a menu/manager plugin

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_ACTIVEOBJECT 1000472

#include "c4d.h"
#include "c4d_symbols.h"
#include "c4d_colors.h"

class Function2 : public TreeViewFunctions
{
	public:

		virtual void*	GetFirst(void *root,void *userdata)
		{
			BaseDocument *doc = (BaseDocument*)root;
			return doc->GetFirstObject();
		}

		virtual void*	GetNext(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetNext();
		}

		virtual void* GetPred(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetPred();
		}

		virtual void*	GetDown(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetDown();
		}

		virtual Bool IsSelected(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetBit(BIT_ACTIVE)!=0;
		}

		virtual String GetName(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetName();
		}

		virtual LONG GetId(void *root,void *userdata,void *obj)
		{
			return (LONG)obj;
		}

		virtual Bool IsOpened(void *root,void *userdata,void *obj)
		{
			return ((BaseList2D*)obj)->GetBit(BIT_OFOLD);
		}

		virtual void Open(void *root,void *userdata,void *obj,Bool onoff)
		{
			if (onoff)
				((BaseList2D*)obj)->SetBit(BIT_OFOLD);
			else
				((BaseList2D*)obj)->DelBit(BIT_OFOLD);
		}

		virtual void Select(void *root,void *userdata,void *obj,LONG mode)
		{
			if (((BaseList2D*)obj)->IsInstanceOf(Obase))
			{
				BaseObject *op = (BaseObject*)obj;
				BaseDocument *doc = op->GetDocument();
				if (doc) doc->SetActiveObject(op,mode);
				EventAdd();
			}
			else if (((BaseList2D*)obj)->IsInstanceOf(Mbase))
			{
				BaseMaterial *op = (BaseMaterial*)obj;
				BaseDocument *doc = op->GetDocument();
				if (doc) doc->SetActiveMaterial(op);
				EventAdd();
			}
		}

		virtual LONG AcceptDragObject(void *root,void *userdata,void *obj,LONG dragtype,void *dragobject, Bool &bAllowCopy)
		{
			if (dragtype==DRAGTYPE_ATOMARRAY && ((AtomArray*)dragobject)->GetCount()==1 && ((AtomArray*)dragobject)->GetIndex(0) && ((AtomArray*)dragobject)->GetIndex(0)->IsInstanceOf(Obase))
				return INSERT_BEFORE|INSERT_AFTER|INSERT_UNDER;

			return 0;
		}

    virtual void InsertObject(void *root,void *userdata,void *obj,LONG dragtype,void *dragobject,LONG insertmode, Bool bCopy)
		{
			if (dragtype==DRAGTYPE_ATOMARRAY && ((AtomArray*)dragobject)->GetCount()==1 && ((AtomArray*)dragobject)->GetIndex(0) && ((AtomArray*)dragobject)->GetIndex(0)->IsInstanceOf(Obase))
			{
				BaseObject *dragop = (BaseObject*)((AtomArray*)dragobject)->GetIndex(0);
				if (!((BaseList2D*)obj)->IsInstanceOf(Obase)) return;

				BaseObject *op = (BaseObject*)obj;

				Matrix merk = dragop->GetMg();
				dragop->Remove();
				switch (insertmode)
				{
					case INSERT_BEFORE: dragop->InsertBefore(op); break;
					case INSERT_UNDER:  dragop->InsertUnder(op); Open(root,userdata,op,TRUE); break;
					default:            dragop->InsertAfter(op); break;
				}
				dragop->SetMg(merk);
				Select(root,userdata,dragop,SELECTION_NEW);
				EventAdd();
			}
		}

		virtual LONG GetDragType(void *root,void *userdata,void *obj)
		{
			if (((BaseList2D*)obj)->IsInstanceOf(Obase)) return DRAGTYPE_ATOMARRAY;
			return NOTOK;
		}

		virtual Bool DoubleClick(void *root,void *userdata,void *obj,LONG col,MouseInfo *mouseinfo)
		{
			if (col=='icon')
			{
				if (((BaseList2D*)obj)->IsInstanceOf(Tbaselist2d))
				{
					((BaseList2D*)obj)->Edit();
					return TRUE;
				}
			}
			return FALSE;
			return FALSE;
		}

		virtual Bool MouseDown(void *root,void *userdata,void *obj,LONG col,MouseInfo *mouseinfo, Bool rightButton)
		{
			if (col=='icon')
			{
				if (((BaseList2D*)obj)->IsInstanceOf(Obase))
				{
					return FALSE;
				}
				else if (((BaseList2D*)obj)->IsInstanceOf(Mbase))
				{
					return FALSE;
				}
			}
			return FALSE;
		}

		virtual LONG GetColumnWidth(void *root,void *userdata,void *obj,LONG col) 
		{ 
			if (col=='icon')
			{
				if (((BaseList2D*)obj)->IsInstanceOf(Obase))
				{
					return 24;
				}
				else if (((BaseList2D*)obj)->IsInstanceOf(Mbase))
				{
					return 24;
				}
			}
			return 0;
		}

		virtual LONG GetLineHeight(void *root,void *userdata,void *obj,LONG col)
		{
			if (col=='icon')
			{
				if (((BaseList2D*)obj)->IsInstanceOf(Obase))
				{
					return 24;
				}
				else if (((BaseList2D*)obj)->IsInstanceOf(Mbase))
				{
					return 24;
				}
			}
			return 0;
		}

		virtual void DrawCell(void *root,void *userdata,void *obj,LONG col,DrawInfo *drawinfo, LONG bgColor)
		{
			if (col=='icon')
			{
				LONG wx,wy,wh,ww;
				if (((BaseList2D*)obj)->IsInstanceOf(Obase))
				{
					BaseObject *op = (BaseObject*)obj;
					IconData icon;
					op->GetIcon(&icon);
					
					wx = drawinfo->xpos;
					wy = drawinfo->ypos;
					ww = drawinfo->width;
					wh = drawinfo->height;

					if (ww>24) { wx += (ww-24)/2; ww = 24; }
					if (wh>24) { wy += (wh-24)/2; wh = 24; }

					drawinfo->frame->DrawSetPen(COLOR_BG);
					drawinfo->frame->DrawBitmap(icon.bmp,wx,wy,ww,wh,icon.x,icon.y,icon.w,icon.h,BMP_ALLOWALPHA|BMP_NORMALSCALED);
				}
				else if (((BaseList2D*)obj)->IsInstanceOf(Mbase))
				{
					BaseMaterial *op = (BaseMaterial*)obj;
					BaseBitmap *bmp = op->GetPreview(0);
					if (bmp)
					{
						wx = drawinfo->xpos;
						wy = drawinfo->ypos;
						ww = drawinfo->width;
						wh = drawinfo->height;

						if (ww>24) { wx += (ww-24)/2; ww = 24; }
						if (wh>24) { wy += (wh-24)/2; wh = 24; }

						drawinfo->frame->DrawSetPen(COLOR_BG);
						drawinfo->frame->DrawBitmap(bmp,wx,wy,ww,wh,0,0,bmp->GetBw(),bmp->GetBh(),BMP_ALLOWALPHA|BMP_NORMALSCALED);
					}
				}
			}
		}
} functable;




class ActiveObjectDialog : public GeDialog
{
	private:
		Bool lock;
		DescriptionCustomGui	*gad;
		TreeViewCustomGui			*tree;

	public:

		virtual Bool CreateLayout(void);
		virtual Bool InitValues(void);
		virtual Bool Command(LONG id,const BaseContainer &msg);
		virtual Bool CoreMessage(LONG id,const BaseContainer &msg);
};


Bool ActiveObjectDialog::CreateLayout(void)
{
	// first call the parent instance
	Bool res = GeDialog::CreateLayout();

	SetTitle("C++SDK Demo - Active Object Properties");

	GroupBegin(0,BFH_SCALEFIT|BFV_SCALEFIT,0,1,String(),0);
		// you can also write "TREEVIEW id { BORDER; } in the resource file

		GroupBegin(0,BFH_SCALEFIT|BFV_SCALEFIT,1,0,String(),0);
			AddCheckbox(1001,BFH_LEFT,0,0,"Lock Element");

			BaseContainer treedata;
			treedata.SetBool(TREEVIEW_BORDER,TRUE);
			tree = (TreeViewCustomGui*)AddCustomGui(10001,CUSTOMGUI_TREEVIEW,String(),BFH_SCALEFIT|BFV_SCALEFIT,0,0,treedata);
			// you can also write "TREEVIEW id { BORDER; } in the resource file
		GroupEnd();

		BaseContainer customgui;
		customgui.SetBool(DESCRIPTION_ALLOWFOLDING,TRUE);
		gad = (DescriptionCustomGui*)AddCustomGui(10000,CUSTOMGUI_DESCRIPTION,String(),BFH_SCALEFIT|BFV_SCALEFIT,0,0,customgui);

	GroupEnd();
	
	if (gad && GetActiveDocument())
	{
		gad->SetObject(GetActiveDocument()->GetActiveObject());
	}

	if (tree)
	{
		BaseContainer layout;
		layout.SetLong('tree',LV_TREE);
		layout.SetLong('icon',LV_USER);
		tree->SetLayout(2,layout);
	}

	return res;
}

Bool ActiveObjectDialog::InitValues(void)
{
	// first call the parent instance
	if (!GeDialog::InitValues()) return FALSE;

	SetBool(1001,lock);
	if (tree)
	{
		tree->SetRoot(GetActiveDocument(),&functable,NULL);
	}

	return TRUE;
}

Bool ActiveObjectDialog::Command(LONG id,const BaseContainer &msg)
{
	switch (id)
	{
		case 1001:
			lock = msg.GetLong(BFM_ACTION_VALUE);
			CoreMessage(EVMSG_CHANGE,BaseContainer());
			break;
	}
	return GeDialog::Command(id,msg);
}



Bool ActiveObjectDialog::CoreMessage(LONG id,const BaseContainer &msg)
{
	switch (id)
	{
		case EVMSG_CHANGE:
			if (CheckCoreMessage(msg) && !lock)
			{
				DescriptionCustomGui *gad = (DescriptionCustomGui*)FindCustomGui(10000,CUSTOMGUI_DESCRIPTION);
				if (gad && GetActiveDocument())
				{
					AutoAlloc<AtomArray> objects; if (!objects) break;
					GetActiveDocument()->GetActiveObjects(objects,TRUE);
					gad->SetObjectList(objects);
				}
				if (tree)
				{
					tree->SetRoot(GetActiveDocument(),&functable,NULL);
				}
			}
			break;
	}
	return GeDialog::CoreMessage(id,msg);
}



class ActiveObjectDialogCommand : public CommandData
{
	private:
		ActiveObjectDialog dlg;

	public:

		virtual Bool Execute(BaseDocument *doc)
		{
			return dlg.Open(TRUE,ID_ACTIVEOBJECT,-1,-1,500,300);
		}

		virtual LONG GetState(BaseDocument *doc)
		{
			return CMD_ENABLED;
		}

		virtual Bool RestoreLayout(void *secret)
		{
			return dlg.RestoreLayout(ID_ACTIVEOBJECT,0,secret);
		}
};

Bool RegisterActiveObjectDlg(void)
{
	// decide by name if the plugin shall be registered - just for user convenience
	String name=GeLoadString(IDS_ACTIVEOBJECT); if (!name.Content()) return TRUE;
	return RegisterCommandPlugin(ID_ACTIVEOBJECT,name,0,NULL,"C++ SDK Active Object",gNew ActiveObjectDialogCommand);
}

