Notifications
Clear all

[Closed] Deleted node and GetAnimByHandle

Hi,
I’m trying to check if my picked node exists in the scene, so I get the handle to its Animatable (GetHandleByAnim) after I pick it and then I try to display the handle, it works fine.
When I delete the node after by Maxscript “delete $” function and try to print the node using the handle (GetAnimByHandle) I got NULL in SDK or undefined in MaxScript, that’s good, but if I delete the node by pressing delete on the keyboard and then display the node by handle (GetAnimByHandle) I got my node’s Animatable returned in SDK and a <Deleted scene node> value.
How to determine if the node exists in the scene using SDK (in case of keyboard delete)? I was trying with isDeleted(Animatable*) method with my INode as parameter, but it also gives me FALSE in this case.

13 Replies

can I ask what sort of plugin you are making the INode reference in ?

It’s a plugin operating on object modifiers, it basically has a pick button (but I didn’t use the pblock2 with TYPE_INODE, I had to use my own pick implementation, so I need to handle all exceptions like deleted node etc).

the correct method of handling in this case would be with references check out PCloud.cpp in objects/particles to see how it handles the custom mesh emitter node. You “add” it to the references that you plugin uses (normally just a pblock) so when it’s deleted your plugin will receive the notification and handle it appropriately.

in the code the custom emitter mesh is called distnode.

also what was the reason for note using the pblock method ? it works well and will handle the save and load where as using the getamimhandle methods will prove problematic as they are not consistent across sessions.

Ok, thanks. I knew about referencing, but I thought that maybe I can check existence just by anim handle.

another example is cammap.cpp in maxsdk\samples\modifiers in the modifier CamMapMod the INode* camRef is the reference to external camera node.

Thanks, I will study the camera map example, it’s looks understandable

i paired down cammap mod to the bare min to handle any node reference and picker


  // external string references need to be supplied 
  // along with the extern getstring function the rollup
  // default max includes here
  #include <3dsmaxport.h>
  
  #define NODE_REF			0
  #define PICKNODE_CLASS_ID	GEOMOBJECT_CLASS_ID
  #define MESSAGE_TITLE	   GetString(IDS_NODEREFERENCING)
  #define MOD_OBJECT_NAME	 GetString(IDS_NODEREF_MOD)
  #define CLASSNAME		   GetString(IDS_NODEREF_MOD)
  
  #define CID_PICK_NODE	CID_USER+0x7055
  
  class PickNodeMode;
  
  class NodeRefMod : public Modifier 
  {
  public:
  
  	static Interface *ip;
  	static HWND hModRollup;
  	static ICustButton *iPick;
  	static PickNodeMode *pickMode;
  	static NodeRefMod *editMod;
  	INode *nodeRef;
  
  	NodeRefMod() : nodeRef(NULL)  {}
  	~NodeRefMod()  {  DeleteAllRefsFromMe(); }
  
  	// --- Methods From Animatable ---
  	void DeleteThis() { delete this; }
  	void GetClassName(TSTR& s) { s = GetString(IDS_NODEREF_MOD); }
  	virtual Class_ID ClassID() { return NODEREF_MOD_CLASS_ID; }
  	void BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev);
  	void EndEditParams(IObjParam *ip, ULONG flags, Animatable *next);	
  
  	RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message);
  	int NumRefs() { return 1; } // camera node
  	RefTargetHandle GetReference(int i);
  	void SetReference(int i, RefTargetHandle rtarg);
  
  	// --- Methods From ReferenceTarget ---
  	RefTargetHandle Clone(RemapDir& remap = DefaultRemapDir());
  
  	// --- Methods From BaseObject ---
  	TCHAR *GetObjectName() { return MOD_OBJECT_NAME; }
  	CreateMouseCallBack* GetCreateMouseCallBack() { return NULL; } 
  
  	// --- Methods From Modifier ---
  	ChannelMask ChannelsUsed() { return PART_GEOM|PART_TOPO|PART_SELECT|TEXMAP_CHANNEL|PART_VERTCOLOR; }
  	ChannelMask ChannelsChanged() { return PART_VERTCOLOR|TEXMAP_CHANNEL; } 
  	Class_ID InputType()   { return Class_ID(TRIOBJ_CLASS_ID, 0); }
  	void ModifyObject(TimeValue t, ModContext &mc,  ObjectState *os, INode *node);
  	Interval LocalValidity(TimeValue t) { return FOREVER; }
  
  	BOOL GetNode(INode *theNode, INode* myNode, TimeValue t); 
  
  };
  
  Interface *NodeRefMod::ip = NULL;
  HWND NodeRefMod::hModRollup = NULL;
  ICustButton *NodeRefMod::iPick = NULL;
  PickNodeMode *NodeRefMod::pickMode = NULL;
  NodeRefMod *NodeRefMod::editMod = NULL;
  
  class PickNodeMode : public PickModeCallback, public PickNodeCallback 
  {
  public:	  
  	NodeRefMod *cm;
  
  	PickNodeMode(NodeRefMod *c) {cm = c;}
  	BOOL HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags);
  	BOOL Pick(IObjParam *ip, ViewExp *vpt);
  	void EnterMode(IObjParam *ip) { cm->iPick->SetCheck(TRUE); }
  	void ExitMode(IObjParam *ip)  { if (cm->iPick) cm->iPick->SetCheck(FALSE); }
  	BOOL RightClick(IObjParam *ip, ViewExp *vpt) { return TRUE; }
  
  	PickNodeCallback *GetFilter() { return this; }
  	BOOL Filter(INode *node);
  };
  
  class PickNodeModRestore : public RestoreObj 
  {
  public:
  	NodeRefMod *cm;
  	PickNodeModRestore(NodeRefMod *c) { cm = c; }
  	void Restore(int isUndo) 
  	{
  		if (cm->editMod == cm && cm->hModRollup)
  		{
  			if (cm->nodeRef)
  				SetWindowText(GetDlgItem(cm->hModRollup, IDC_NODE_NAME), cm->nodeRef->GetName());
  			else
  				SetWindowText(GetDlgItem(cm->hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
  		}						  
  	}
  	void Redo() 
  	{
  		if (cm->editMod == cm && cm->hModRollup && cm->nodeRef)
  		{
  			if (cm->nodeRef)
  			   SetWindowText(GetDlgItem(cm->hModRollup, IDC_NODE_NAME), cm->nodeRef->GetName());
  			else
  			   SetWindowText(GetDlgItem(cm->hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
  		}
  	}
  	TSTR Description() {  return TSTR(GetString(IDS_PICK_NODE));  }
  };
  
  class NodeRefModClassDesc : public ClassDesc 
  {
  public:
  	int			IsPublic()						{ return 1; }
  	void		*Create(BOOL loading = FALSE)	{ return new NodeRefMod; }
  	const TCHAR	*ClassName()					{ return CLASSNAME; }
  	SClass_ID	SuperClassID()					{ return OSM_CLASS_ID; }
  	Class_ID	ClassID()						{ return NODEREF_MOD_CLASS_ID; }
  	const TCHAR *Category()						{ return GetString(IDS_PG_MOD_CATEGORY); }
  };
  static NodeRefModClassDesc NodeRefModDesc;
  ClassDesc* GetNodeRefModDesc() { return &NodeRefModDesc; }
  
  
  static INT_PTR CALLBACK NodeRefModDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
  {
     NodeRefMod *cm = DLGetWindowLongPtr<NodeRefMod *>(hWnd);
     if (!cm && msg != WM_INITDIALOG ) return FALSE;
  
     switch (msg)
     {
  	  case WM_INITDIALOG:
  		 cm = (NodeRefMod *)lParam;
  		 DLSetWindowLongPtr(hWnd, cm);
  		 cm->iPick = GetICustButton(GetDlgItem(hWnd, IDC_NODE_PICK));
  		 cm->iPick->SetText(GetString(IDS_PICK_NODE));
  		 cm->iPick->SetType(CBT_CHECK);
  		 cm->iPick->SetHighlightColor(GREEN_WASH);
  		 cm->iPick->SetCheckHighlight(TRUE);
  
  		 if (cm->nodeRef)
  			SetWindowText(GetDlgItem(hWnd, IDC_NODE_NAME), cm->nodeRef->GetName());
  		 else
  			SetWindowText(GetDlgItem(hWnd, IDC_NODE_NAME), GetString(IDS_NONE));
  		 return TRUE;
  
  
  	  case WM_DESTROY:
  		 ReleaseICustButton(cm->iPick);
  		 cm->iPick = NULL;
  		 return TRUE;
  
  	  case WM_LBUTTONDOWN: 
  	  case WM_LBUTTONUP:   
  	  case WM_MOUSEMOVE:
  		 cm->ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
  		 return TRUE;
  
  	  case WM_COMMAND:
  		 switch (LOWORD(wParam))
  		 {
  			case IDC_NODE_PICK:
  			   if (cm->ip->GetCommandMode()->ID() == CID_PICK_NODE)
  				  cm->ip->SetStdCommandMode(CID_OBJMOVE);
  			   else
  				  cm->ip->SetPickMode(cm->pickMode);
  			   return TRUE;
  		 }  
     }
     return FALSE; 
  }
  
  void NodeRefMod::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev) 
  {
  	this->ip = ip;
  	pickMode = new PickNodeMode(this);
  	editMod = this;
  	hModRollup = ip->AddRollupPage(hInstance, MAKEINTRESOURCE(IDD_NODEREF_MOD), NodeRefModDlgProc, GetString(IDS_NODEREFERENCING),
  						(LPARAM)this, 0);	
  }
  
  void NodeRefMod::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next) 
  {
  	ip->DeleteRollupPage(hModRollup);
  	ip->ClearPickMode();
  	delete pickMode;
  	pickMode = NULL;
  	editMod = NULL; 
  	hModRollup = NULL;
  	this->ip = NULL;
  }
  
  void NodeRefMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node)
  {
     if (!nodeRef) return;
  // modifier code goes here
  
  }
  
  RefTargetHandle NodeRefMod::GetReference(int i) 
  {
  	switch(i) 
  	{
  		case NODE_REF: return (RefTargetHandle)nodeRef;
  		default: return NULL;
  	}
  }
  
  void NodeRefMod::SetReference(int i, RefTargetHandle rtarg) 
  { 
  	switch(i) 
  	{
  		case NODE_REF: nodeRef = (INode *) rtarg; 
  		return;
  	}
  }
  
  RefResult NodeRefMod::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message) 
  {
  	switch (message) 
  	{
  		case REFMSG_TARGET_DELETED:   
  			if (hTarget == nodeRef) 
  			{
  				nodeRef = NULL;
  				if(hModRollup)
  					SetWindowText(GetDlgItem(hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
  			}
  			break;
  	}
  	return REF_SUCCEED; 
  }
  
  RefTargetHandle NodeRefMod::Clone(RemapDir& remap) 
  {
  	NodeRefMod *newMod = new NodeRefMod();
  
  	if(nodeRef)
  		newMod->ReplaceReference(NODE_REF, nodeRef);
  	else
  		newMod->nodeRef = NULL;
  	newMod->pickMode = NULL;
  	newMod->editMod = NULL; 
  	BaseClone(this, newMod, remap);
  	return newMod;
  }
  
  BOOL NodeRefMod::GetNode(INode *theNode, INode* myNode, TimeValue t) 
  {
  	if(theNode->TestForLoop(FOREVER,this)==REF_SUCCEED) 
  	{
  		theHold.Begin();
  		ReplaceReference(NODE_REF, (RefTargetHandle)theNode);
  		theHold.Put(new PickNodeModRestore(this));
  		theHold.Accept(GetString(IDS_PICKNODE));
  		NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
  		return TRUE;
  	} 
  	return FALSE;
  }
  
  //*************************************************************************************
  // PickNodeMode
  //*************************************************************************************
  
  BOOL PickNodeMode::Filter(INode *node) 
  {
  	if (node) 
  	{
  		ObjectState os = node->EvalWorldState(0);
  		if (os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
  		{
  			SetCursor(cm->ip->GetSysCursor(SYSCUR_SELECT));
  			return TRUE;
  		}
  	}
  	return FALSE;
  }
  
  BOOL PickNodeMode::HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags) 
  {
  	INode *node = cm->ip->PickNode(hWnd, m);
  	if (node) 
  	{
  		ObjectState os = node->EvalWorldState(0);
  		if(os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
  		{
  			SetCursor(cm->ip->GetSysCursor(SYSCUR_SELECT));
  			return TRUE;
  		}
  	}
  	return FALSE;
  }
  
  BOOL PickNodeMode::Pick(IObjParam *ip, ViewExp *vpt) 
  {
  	INode *node = vpt->GetClosestHit();
  	if (node) 
  	{
  		ObjectState os = node->EvalWorldState(0);
  		if (os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
  		{
  			if(cm->GetNode(node, NULL, ip->GetTime())) 
  			{
  				SetWindowText(GetDlgItem(cm->hModRollup, IDC_NODE_NAME), node->GetName());
  				cm->ip->SetStdCommandMode(CID_OBJMOVE);
  				cm->ip->RedrawViews(cm->ip->GetTime());
  			} 
  			else 
  			{
  				TSTR buf = GetString(IDS_ILLEGALNODE);
  				MessageBox(ip->GetMAXHWnd(), buf, MESSAGE_TITLE, MB_OK|MB_ICONEXCLAMATION);
  			}
  		}
  	}
  	return TRUE;
  }
  

the dialog resource

IDD_NODEREF_MOD DIALOGEX 0, 0, 108, 53
  STYLE DS_SETFONT | WS_CHILD
  FONT 8, "MS Sans Serif", 0, 0, 0x0
  BEGIN
  	GROUPBOX		"Current Node",IDC_STATIC,3,3,102,45,WS_GROUP
  	LTEXT		   "None",IDC_NODE_NAME,10,15,89,8
  	CONTROL		 "",IDC_NODE_PICK,"CustButton",WS_GROUP | WS_TABSTOP,9,29,90,14
  END
  

How a node reference might sit along side param block 2, though it’s much easier to use the ParamBlockDesc2, TYPE_PICKNODEBUTTON, TYPE_INODE with a p_validator to handle this type of thing

#include <3dsmaxport.h>
 // default headers
 
 #define PBLOCK_REF			0
 #define NODE_REF			1
 
 #define PICKNODE_CLASS_ID	GEOMOBJECT_CLASS_ID
 #define MESSAGE_TITLE	   GetString(IDS_NODEREFERENCING)
 #define MOD_OBJECT_NAME	 GetString(IDS_NODEREF_MOD)
 #define CLASSNAME		   GetString(IDS_NODEREF_MOD)
 
 #define CID_PICK_NODE	CID_USER+0x7055
 
 class PickNodeMode;
 
 class NodeRefMod : public Modifier 
 {
 public:
 
 	static Interface *ip;
 	static HWND hModRollup;
 	static ICustButton *iPick;
 	static PickNodeMode *pickMode;
 	static NodeRefMod *editMod;
 	INode*			nodeRef;
 	IParamBlock2*	pblock;
 
 	NodeRefMod();
 	~NodeRefMod()  {  DeleteAllRefsFromMe(); }
 
 	// --- Methods From Animatable ---
 	void DeleteThis() { delete this; }
 	void GetClassName(TSTR& s)	{ s = GetString(IDS_NODEREF_MOD); }
 	virtual Class_ID ClassID()	{ return NODEREF_MOD_CLASS_ID; }
 	void BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev);
 	void EndEditParams(IObjParam *ip, ULONG flags, Animatable *next);	
 
 	RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message);
 
 	int NumRefs()		{ return 2; } 
 	RefTargetHandle GetReference(int i);
 	void SetReference(int i, RefTargetHandle rtarg);
 
 	int NumParamBlocks()						{ return 1; }
 	IParamBlock2 *GetParamBlock(int i)			{ return pblock; }
 	IParamBlock2 *GetParamBlockByID(short id)	{ return (pblock->ID() == id) ? pblock : NULL; }
 
 	int NumSubs()				{ return 2; }
 	Animatable* SubAnim(int i)	{ return GetReference(i); }
 	TSTR SubAnimName(int i)		{ return GetString (IDS_PARAMETERS); }
 	
 	// --- Methods From ReferenceTarget ---
 	RefTargetHandle Clone(RemapDir& remap = DefaultRemapDir());
 
 	// --- Methods From BaseObject ---
 	TCHAR *GetObjectName() { return MOD_OBJECT_NAME; }
 	CreateMouseCallBack* GetCreateMouseCallBack() { return NULL; } 
 
 	// --- Methods From Modifier ---
 	ChannelMask ChannelsUsed() { return PART_GEOM|PART_TOPO|PART_SELECT|TEXMAP_CHANNEL|PART_VERTCOLOR; }
 	ChannelMask ChannelsChanged() { return PART_VERTCOLOR|TEXMAP_CHANNEL; } 
 	Class_ID InputType()   { return Class_ID(TRIOBJ_CLASS_ID, 0); }
 	void ModifyObject(TimeValue t, ModContext &mc,  ObjectState *os, INode *node);
 	Interval LocalValidity(TimeValue t) { return FOREVER; }
 
 	BOOL GetNode(INode *theNode, INode* myNode, TimeValue t); 
 };
 
 //****************************************************************************************
 
 Interface *NodeRefMod::ip = NULL;
 HWND NodeRefMod::hModRollup = NULL;
 ICustButton *NodeRefMod::iPick = NULL;
 PickNodeMode *NodeRefMod::pickMode = NULL;
 NodeRefMod *NodeRefMod::editMod = NULL;
 
 //****************************************************************************************
 
 class NodeRefModClassDesc : public ClassDesc2 
 {
 public:
 	int			IsPublic()						{ return 1; }
 	void		*Create(BOOL loading = FALSE)	{ return new NodeRefMod(); }
 	const TCHAR	*ClassName()					{ return CLASSNAME; }
 	SClass_ID	SuperClassID()					{ return OSM_CLASS_ID; }
 	Class_ID	ClassID()						{ return NODEREF_MOD_CLASS_ID; }
 	const TCHAR *Category()						{ return GetString(IDS_PG_MOD_CATEGORY); }
 	const TCHAR* InternalName()					{ return _T("NodeRef"); }	
 	HINSTANCE	 HInstance()					{ return hInstance; }	
 };
 
 static NodeRefModClassDesc NodeRefModDesc;
 ClassDesc* GetNodeRefModDesc() { return &NodeRefModDesc; }
 
 //****************************************************************************************
 
 class PickNodeMode : public PickModeCallback, public PickNodeCallback 
 {
 public:	  
 	NodeRefMod *mod;
 
 	PickNodeMode(NodeRefMod *c) {mod = c;}
 	BOOL HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags);
 	BOOL Pick(IObjParam *ip, ViewExp *vpt);
 	void EnterMode(IObjParam *ip) { mod->iPick->SetCheck(TRUE); }
 	void ExitMode(IObjParam *ip)  { if (mod->iPick) mod->iPick->SetCheck(FALSE); }
 	BOOL RightClick(IObjParam *ip, ViewExp *vpt) { return TRUE; }
 
 	PickNodeCallback *GetFilter() { return this; }
 	BOOL Filter(INode *node);
 };
 
 //*************************************************************************************
 
 enum noderef_pblock_id { knref_params };
 enum noderef_pblock_param_id { knref_offset };
 
 static ParamBlockDesc2 noderef_param_desc( knref_params, _T("Node Ref Params"), IDS_PARAMETERS, 
 					&NodeRefModDesc, P_AUTO_CONSTRUCT | P_AUTO_UI, PBLOCK_REF, 
 
 	IDD_NODEREF_MOD, IDS_PARAMETERS, 0, 0, NULL,
 
 	knref_offset,	_T("offset"),   TYPE_FLOAT,	0,	IDS_NODEREF_OFFSET,
 		p_default,		1.0f,
 		p_range,		-999999999.0f, 999999999.0f,
 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT, IDC_NODEREF_OFFSET_EDIT, IDC_NODEREF_OFFSET_SPIN, 0.1f, 
 	end,
 	end
 );
 
 //*************************************************************************************
 
 class PickNodeModRestore : public RestoreObj 
 {
 public:
 	NodeRefMod* mod;
 	PickNodeModRestore(NodeRefMod *c) { mod = c; }
 	void Restore(int isUndo) 
 	{
 		if (mod->editMod == mod && mod->hModRollup)
 		{
 			if (mod->nodeRef)
 				SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), mod->nodeRef->GetName());
 			else
 				SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
 		}						  
 	}
 	void Redo() 
 	{
 		if (mod->editMod == mod && mod->hModRollup && mod->nodeRef)
 		{
 			if (mod->nodeRef)
 				SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), mod->nodeRef->GetName());
 			else
 				SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
 		}
 	}
 	TSTR Description() {  return TSTR(GetString(IDS_PICK_NODE));  }
 };
 
 //****************************************************************************************
 
 class NodeRefModDlgProc : public ParamMap2UserDlgProc 
 {
 public:
 	NodeRefMod*	mod;
 
 	NodeRefModDlgProc(NodeRefMod* m) { mod = m;}
 	INT_PTR DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
 	void InitPanel(TimeValue t);
 	void DeleteThis() { delete this; }
 };
 
 //*************************************************************************************
 
 void NodeRefModDlgProc::InitPanel(TimeValue t)
 { 
 	if(!mod->hModRollup) 
 		return;
 
 	mod->iPick = GetICustButton(GetDlgItem(mod->hModRollup, IDC_NODE_PICK));
 	mod->iPick->SetText(GetString(IDS_PICK_NODE));
 	mod->iPick->SetType(CBT_CHECK);
 	mod->iPick->SetHighlightColor(GREEN_WASH);
 	mod->iPick->SetCheckHighlight(TRUE);
 
 	if(mod->nodeRef)
 		SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), mod->nodeRef->GetName());
 	else
 		SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
 }
 
 //*************************************************************************************
 
 INT_PTR NodeRefModDlgProc::DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 	mod->hModRollup = hWnd; 
 	switch (msg)
 	{
 		case WM_INITDIALOG:
 		{
 			InitPanel(t);
 			break;
 		}  
 		case WM_DESTROY:
 			ReleaseICustButton(mod->iPick);
 			mod->iPick = NULL;
 			return TRUE;
 
 		case WM_COMMAND:
 
 			switch (LOWORD(wParam))
 			{
 				case IDC_NODE_PICK:
 					if (mod->ip->GetCommandMode()->ID() == CID_PICK_NODE)
 						mod->ip->SetStdCommandMode(CID_OBJMOVE);
 					else
 						mod->ip->SetPickMode(mod->pickMode);
 					return TRUE;
 			}  
 	}
 	return FALSE; 
 }
 
 //*************************************************************************************
 
 NodeRefMod::NodeRefMod() : nodeRef(NULL),  pblock(NULL) 
 {
 	NodeRefModDesc.MakeAutoParamBlocks(this);
 }
 
 //*************************************************************************************
 
 void NodeRefMod::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev) 
 {
 	this->ip = ip;	
 	pickMode = new PickNodeMode(this);
 	editMod  = this;
 
 // throw up all the appropriate auto-rollouts
 
 	TimeValue t = ip->GetTime();
 	NotifyDependents(Interval(t,t), PART_ALL, REFMSG_BEGIN_EDIT);
 
 	SetAFlag(A_MOD_BEING_EDITED);
 	NodeRefModDesc.BeginEditParams(ip, this, flags, prev);
 	noderef_param_desc.SetUserDlgProc(new NodeRefModDlgProc(this));
 }
 
 //****************************************************************************************
 
 void NodeRefMod::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next) 
 {
 	TimeValue t = ip->GetTime();
 	ClearAFlag(A_MOD_BEING_EDITED);
 	NotifyDependents(Interval(t,t), PART_ALL, REFMSG_END_EDIT);
 
 	NodeRefModDesc.EndEditParams(ip, this, flags, next);
 	delete pickMode;
 	pickMode = NULL;
 	this->ip = NULL;
 	hModRollup = NULL;
 	editMod  = NULL;
 }
 
 //****************************************************************************************
 
 void NodeRefMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node)
 {
 	if(!nodeRef) return;
 // modifier code goes here
 
 }
 
 //*************************************************************************************
 
 RefTargetHandle NodeRefMod::GetReference(int i) 
 {
 	switch(i) 
 	{
 		case PBLOCK_REF: return (RefTargetHandle)pblock;
 		case NODE_REF:   return (RefTargetHandle)nodeRef;
 		default: return NULL;
 	}
 }
 
 //*************************************************************************************
 
 void NodeRefMod::SetReference(int i, RefTargetHandle rtarg) 
 { 
 	switch(i) 
 	{
 		case PBLOCK_REF: 
 			pblock = (IParamBlock2*)rtarg; 
 			return;
 		case NODE_REF: 
 			nodeRef = (INode*)rtarg; 
 			return;
 	}
 }
 
 //*************************************************************************************
 
 RefResult NodeRefMod::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message) 
 {
 	switch (message) 
 	{
 		case REFMSG_TARGET_DELETED:   
 			if(hTarget == nodeRef) 
 			{
 				nodeRef = NULL;
 				if(hModRollup)
 					SetWindowText(GetDlgItem(hModRollup, IDC_NODE_NAME), GetString(IDS_NONE));
 			}
 			break;
 	}
 	return REF_SUCCEED; 
 }
 
 //*************************************************************************************
 
 RefTargetHandle NodeRefMod::Clone(RemapDir& remap) 
 {
 	NodeRefMod *newMod = new NodeRefMod();
 
 	newMod->ReplaceReference(PBLOCK_REF, remap.CloneRef(pblock));
 	newMod->nodeRef = NULL;
 	if(nodeRef) newMod->ReplaceReference(NODE_REF, nodeRef);
 	
 	newMod->pickMode = NULL;
 	newMod->editMod = NULL; 
 	BaseClone(this, newMod, remap);
 	return newMod;
 }
 
 //****************************************************************************************
 
 BOOL NodeRefMod::GetNode(INode *theNode, INode* myNode, TimeValue t) 
 {
 	if(theNode->TestForLoop(FOREVER,this) == REF_SUCCEED) 
 	{
 		theHold.Begin();
 		ReplaceReference(NODE_REF, (RefTargetHandle)theNode);
 		theHold.Put(new PickNodeModRestore(this));
 		theHold.Accept(GetString(IDS_PICKNODE));
 		NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
 		return TRUE;
 	} 
 	return FALSE;
 }
 
 //*************************************************************************************
 // PickNodeMode
 //*************************************************************************************
 
 BOOL PickNodeMode::Filter(INode *node) 
 {
 	if(node) 
 	{
 		ObjectState os = node->EvalWorldState(0);
 		if(os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
 		{
 			SetCursor(mod->ip->GetSysCursor(SYSCUR_SELECT));
 			return TRUE;
 		}
 	}
 	return FALSE;
 }
 
 //****************************************************************************************
 
 BOOL PickNodeMode::HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags) 
 {
 	INode* node = mod->ip->PickNode(hWnd, m);
 	if(node) 
 	{
 		ObjectState os = node->EvalWorldState(0);
 		if(os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
 		{
 			SetCursor(mod->ip->GetSysCursor(SYSCUR_SELECT));
 			return TRUE;
 		}
 	}
 	return FALSE;
 }
 
 //****************************************************************************************
 
 BOOL PickNodeMode::Pick(IObjParam *ip, ViewExp *vpt) 
 {
 	INode* node = vpt->GetClosestHit();
 	if (node) 
 	{
 		ObjectState os = node->EvalWorldState(0);
 		if (os.obj->SuperClassID() == PICKNODE_CLASS_ID) 
 		{
 			if(mod->GetNode(node, NULL, ip->GetTime())) 
 			{
 				SetWindowText(GetDlgItem(mod->hModRollup, IDC_NODE_NAME), node->GetName());
 				mod->ip->SetStdCommandMode(CID_OBJMOVE);
 				mod->ip->RedrawViews(mod->ip->GetTime());
 			} 
 			else 
 			{
 				TSTR buf = GetString(IDS_ILLEGALNODE);
 				MessageBox(ip->GetMAXHWnd(), buf, MESSAGE_TITLE, MB_OK|MB_ICONEXCLAMATION);
 			}
 		}
 	}
 	return TRUE;
 }
 
 //*************************************************************************************
 //*************************************************************************************

new rollup

IDD_NODEREF_MOD DIALOGEX 0, 0, 108, 92
 STYLE DS_SETFONT | WS_CHILD
 FONT 8, "MS Sans Serif", 0, 0, 0x0
 BEGIN
 	GROUPBOX		"Current Node",IDC_STATIC,3,3,102,45,WS_GROUP
 	LTEXT		   "None",IDC_NODE_NAME,10,15,89,8
 	CONTROL		 "",IDC_NODE_PICK,"CustButton",WS_GROUP | WS_TABSTOP,9,29,90,14
 	RTEXT		   "Offset:",IDC_NODEREF_OFFSET_STAT,12,55,30,8
 	CONTROL		 "",IDC_NODEREF_OFFSET_EDIT,"CustEdit",WS_GROUP | WS_TABSTOP,44,54,31,10
 	CONTROL		 "",IDC_NODEREF_OFFSET_SPIN,"SpinnerControl",WS_GROUP,76,54,7,10
 END

Klvnk, I have a problem with your code. My plugin is in fact a SimpleObject, and when I implement the SetReference method I can’t create my object anymore, because SimpleObject has it’s own implementation of SetReference:

“SimpleObject (…) also provides implementations of ReferenceMaker::GetReference() and SetReference() which get and set the pblock2 pointer.”

So when I override the original function with your code I’m causing problems with pblock2 I guess. Do you know how to handle it properly?

Page 1 / 2