Notifications
Clear all

[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
13 Replies

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).

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

you can’t do it with mxs, but probably can with sdk. do you need an sdk solutions?

isValidValue is undefined

1 Reply
(@swordslayer)
Joined: 11 months ago

Posts: 0

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 ?

Page 1 / 2