[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.
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.
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?