[Closed] AddRollout in modify panel
AddRollout/RemoveRollout can both be used in modify panel when the rollout in question is a rollout of the current active object, but when using a rollout of another object, that rollout gets instead added to the utility panel.
Any idea how to add it in the modify panel instead? In this example, toggling default and custom rollout works as expected but toggling 3-rd party rollout doesn’t:
plugin simpleObject Cuboid
name:"Cuboid"
classID:#(0x133067, 0x54374)
category:"Scripted Primitives"
(
parameters main rollout:params (size type:#worldUnits ui:spnSize;)
rollout params "Params" (spinner spnSize "Size: " type:#worldUnits;)
on buildMesh do mesh = (createInstance Box width:size length:size height:size).mesh
tool create numPoints:2
(
on mousePoint click do if click == 1 do
nodeTM.translation = gridPoint
on mouseMove click do if click == 2 do
size = 2 * amax (abs gridDist.x) (abs gridDist.y)
)
)
plugin helper testRollouts
name:"Test Rollouts" classID:#(0x5eaf0b57, 0x4af67cca) invisible:on
(
local cuboid = createInstance ::Cuboid size:15
local rolloutVariable = rollout rolloutVariable "On Demand Rollout"
(
label lblVarDesc "Added on demand"
)
rollout params "Parameters"
(
button btnToggleRollout "Toggle default rollout"
button btnAddVarRollout "Toggle custom rollout"
button btn3rdPartyRollout "Toggle 3rd-party rollout"
on params open do
addRollout rolloutVariable
on btnToggleRollout pressed do
if this.toggled.open then removeRollout this.toggled
else addRollout this.toggled
on btnAddVarRollout pressed do
if rolloutVariable.open then removeRollout rolloutVariable
else addRollout rolloutVariable
on btn3rdPartyRollout pressed do if isValidValue this.cuboid do
if this.cuboid.params.open then removeRollout this.cuboid.params
else addRollout this.cuboid.params
on params close do
removeRollout rolloutVariable
)
rollout toggled "Default Rollout"
(
label lblDefDesc "Added by default"
)
)
setCommandPanelTaskMode #modify
testRollouts isSelected:on
Basically, I’m looking for the same functionality the addPluginRollouts offers, just for the modify panel. I’d be glad for any pointers (not limited to maxscript, too).
you can’t do it with mxs, but probably can with sdk. do you need an sdk solutions?
I think it’s 2017+, doesn’t really matter here though.
Any solution would be great, even a pointer where to look since this is an area where I’m totally lost and don’t know where to look either. There’s no example code in the SDK samples that would show how to add rollouts connected to another object, is there?
Unfortunately, I, too, do not have a ready decision on this matter. As you correctly said, this is a dark area, which is practically not documented and is not represented by examples. But there are some thoughts …
The only possibility I see is using IRollupWindow :: AppendRollup … and it needs some trick
another way is directly add a rollout to MSPlugin’s rollout array. It works! But… it works on class definition level, and also needs a trick to keep added rollout mapped to a corresponding parameter block
it’s trivial beyond belief in the sdk (and there are several examples camera.cpp and modifiers\bonesdef\dlgproc.cpp etc)
point helper node stored in a pblock add this to your BeginEditParams routine
INode* node = pblock->GetINode(kptsel_point_node);
if(node)
{
Object* obj = node->GetObjectRef();
if(obj)
{
Object* bobj = obj->FindBaseObject();
if(bobj)
bobj->BeginEditParams(ip, flags);
}
}
and this to your EndEditParams routine
INode* node = pblock->GetINode(kptsel_point_node);
if(node)
{
Object* obj = node->GetObjectRef();
if(obj)
{
Object* bobj = obj->FindBaseObject();
if(bobj)
bobj->EndEditParams(ip, flags);
}
}
in the above case you need to add
IRollupWindow* ruw = ip->GetCommandPanelRollup();
if(ruw)
ruw->SetPanelTitle (ruw->GetNumPanels() - 1, _T("Point Params"));
directly after the bobj->BeginEditParams(ip, flags); line as it otherwize it would just read “parameters” (there is more robust way of coding this but you get the gist). There is other stuff you would need to implement for completeness in the above case you would need to add a PBAccessor::Set to handle the case where the picked node is changed (or changed via mxs while this is being edited)
the pb accessor code can be handle like so
inline void BeginEdit(INode* node, IObjParam* ip, ULONG flags)
{
if(!node) return;
Object* obj = node->GetObjectRef();
if(!obj) return;
Object* bobj = obj->FindBaseObject();
if(bobj)
{
bobj->BeginEditParams(ip, flags);
IRollupWindow* ruw = ip->GetCommandPanelRollup();
if(ruw)
ruw->SetPanelTitle (ruw->GetNumPanels() - 1, node->GetName());
}
}
inline void EndEdit(INode* node, IObjParam* ip, ULONG flags)
{
if(!node) return;
Object* obj = node->GetObjectRef();
if(!obj) return;
Object* bobj = obj->FindBaseObject();
if(bobj) bobj->EndEditParams(ip, flags);
}
class pointselect_accessor : public PBAccessor
{
public:
void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t) // set from v
{
PointSelectMod* mod = static_cast<PointSelectMod*>(owner);
if(!mod) return;
switch(id)
{
case kptsel_point_node:
{
if(!mod->TestAFlag(A_MOD_BEING_EDITED)) // are we being edited ? if not bum out
break;
EndEdit(mod->pblock->GetINode(kptsel_point_node), mod->ip, END_EDIT_REMOVEUI); // down with the old
if(v.r)
BeginEdit(static_cast<INode*>(v.r), mod->ip, 0); // up with the new
}
}
}
};
static pointselect_accessor pb_accessor;
for objects that might be in the create panel you’ll need to store the current edit status within the object so you can tell if it’s in the create or modify panels
Wonderful, that should do the trick Thanks a lot!
Edit: works great (the only unexpected thing is the order the rollouts are added seems kinda random but that doesn’t really matter in my case anyway).
there is another condition that can crop up if a rare one, the pblock ref to the node being set to undefined via maxscript while the modifier/object is being edited. It doesn’t get handled properly by the accessor set (might be a bug on the max side) though you can handle it via a custom validator as so.
class pointselect_validator : public PBValidator
{
private:
PointSelectMod* mod;
BOOL Validate(PB2Value &v)
{
INode *current_node = mod->pblock->GetINode(kptsel_point_node);
if(v.r == NULL) // mxs $.modifiers[#PointSelect].operand = undefined
{
if(current_node && mod->TestAFlag(A_MOD_BEING_EDITED))
EndEdit(current_node, mod->ip, END_EDIT_REMOVEUI);
return TRUE;
}
INode *node = static_cast<INode*>(v.r);
if (node == current_node)) return FALSE;
if (node->TestForLoop(FOREVER, static_cast<ReferenceMaker *>(mod)) != REF_SUCCEED) return FALSE;
Object* obj = node->GetObjectRef(); // a call to find baseobject after this is you want to allow picking object with modifiers
if(obj && obj->ClassID() == Class_ID(POINTHELP_CLASS_ID,0)) return TRUE;
return FALSE;
}
// neat hack so we can use this in pblock definition and not have to "attach" it in BeginEditParams
BOOL Validate(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex)
{
mod = static_cast<PointSelectMod*>(owner);
return this->Validate(v);
}
};
static pointselect_validator pb_validator;
Edit: works great (the only unexpected thing is the order the rollouts are added seems kinda random but that doesn’t really matter in my case
anyway).
ParamBlockDesc2 Class Reference, page in the help specificallly BYTE flags P_HASCATEGORY you can then force it to be positioned last with large int value in the ParamBlockDesc2
static ParamBlockDesc2 std2_shader_blk ( std2_shader,
_M("shaderParameters"), 0, &stdmtl2CD,
P_AUTO_CONSTRUCT + P_AUTO_UI + P_HASCATEGORY, SHADER_PB_REF,
//rollout
IDD_DMTL_SHADER4, IDS_KE_SHADER, 0, 0, &shaderDlgProc, [b]4900[/b],
// params
std2_shader_type, _M("shaderType"), TYPE_INT, 0, IDS_JW_SHADERTYPE,,
4900 in this case
Out of interest, are you using an InterfaceServer in the dependancy ?