Jump to content
Developer Wiki and Function Reference Links ×

Nested plugin objects


KN_Michael

Recommended Posts

Is it possible to create nested plugin objects - similar to what walls and doors, windows do?

 

I want to place my own plugin objects inside other plugin objects but what I tried so far does not work, so I wonder about following:

 

1) Is this technically supported?

2) If yes, how would the process to create such a hierarchy work like?

Link to comment

It's possible, but there's not really built-in mechanisms for managing the inner plug-in. You basically have two options:

 

1. Insert the inner PIO in the profile group of the outer PIO. On regeneration, your outer PIO makes a copy of the inner PIO from the profile group into its main geometry. The user would have to edit the profile group in order to modify the inner PIO.

 

2. Create a parent/child link between objects. You would use a hidden data field to record a link between objects (saving the UUID for each object works well). You have to account for all the various possibilities of the relationship: what if one deletes, what if one moves, what if one changes layer, etc.

  • Like 1
Link to comment

Thanks for the ideas and warnings.

 

@JBenghiat

Regarding your suggestion:

  • In solution 1 I am not able to edit properties of sub objects via object info pane if I understand correctly, do I?
  • In solution 2 - there is no way to link objects with each other automatically via some constraints, so everything, even moving (as you mention) must be done manually by reacting to events of the parent, correct?

I may go with solution 2 even though it means a lot of manual work - I will evaluate this solution though

 

Edited by KN_Michael
Link to comment

Option 2 is probably the hardest because you have to be carefull with undo and manage all actions properly for two objects that are "bound" on a parametric base.

 

There is another option 3. In the SDK you can choose if the recalculate event removes everything prior to recreation. The inner object would reside permanently in the outer. For simplicity option 1 is probably the best choice.

 

It also depends of the interaction you need. Does the outer control the inner? Or in reverse order? If it's just a couple fields you could duplicate them in the parent object, which update the inner object with those same fields. This is probably the easiest method.

If you use the option of the profile group, the benefit is that you can have a button in the info palette that opens the profile group and preselects the inner object, from that point the inner objec's palette is shown for direct access. On exit, you can have the parent object reset and use the new values.

 

You can  also extend the object info palette with custom fields that are linked to any object or data as long as you handle the conversion as you need to bypass the normal translation from/to, I'm doing this with several plug-ins combined with a selector widget (kWidgetSubSelection) that allows me to iterate several inner objects within the object info palette. This is great for a couple fields but those other options are probably better for larger palettes.

 

Some small snippets for indication.

 

bool IProvider_MEPComponent::OnWidgetChange(SShapePaneWidgetOnWidgetChange& data, bool& outNeedReset, bool& outChangeOk)
else if(fWidgetsContainer.IsWidget(WidgetId, "ToggleLegs"))
    {
        outNeedReset = false;
        eventHandled = false;
        
        using namespace VectorWorks::Extension;
        
        if(fLegs.size() > 0)
        {
            IShapePaneWidgetAccess::ESubSelButton CurrentButton = data.fWidgetAccess->GetCurrentButton();
            if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_CurrentButtonDown)
            {
                HighlightActiveLeg(&data);
            }
            else if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_NextButtonDown)
            {
                fNumActiveLeg++;
                HighlightActiveLeg(&data);
            }
            else if(CurrentButton == IShapePaneWidgetAccess::ESubSelButton::eSubSelButton_PrevButtonDown)
            {
                if(fNumActiveLeg == 0)
                {
                    fNumActiveLeg = fLegs.size() -1;
                }
                else
                {
                    fNumActiveLeg--;
                }
                
                HighlightActiveLeg(&data);
            }
            
            else if(CurrentButton == IShapePaneWidgetAccess::eSubSelButton_CurrentButtonUp || CurrentButton == IShapePaneWidgetAccess::eSubSelButton_NextButtonUp || CurrentButton == IShapePaneWidgetAccess::eSubSelButton_PrevButtonUp)
            {
                data.fWidgetAccess->ClearHighlightPoint();
                data.fWidgetAccess->SetValueBool(data.fViewWidget, false);
            }
        }
    }

 

 

You need to manage TransferValue in both directions for widgets not bound to default parameters of your object. In this case I'm referencing data from whichever inner object is the active selection from the previous selector widget.

bool IProvider_MEPComponent::TransferValue(VectorWorks::Extension::SShapePaneWidgetTransferValue &data)
{
    using namespace VectorWorks::Extension;
    
    bool handled = false;
    
    // For some widgets we need to switch over the record format to the active connector...
    if(
       fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType") ||
       fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length") ||
       fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape") ||
       fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width") ||
       fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height")
       )
    {
        if(fLegs.size() > 0)
        {
            sUserData_JunctionLeg* pLeg = &fLegs[fNumActiveLeg % fLegs.size()];
            
            if(data.fTransferToView)
            {
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType"))
                {
                    TXString strValue;
                    strValue.itoa(pLeg->DimensionType);
                    data.fWidgetAccess->SetValueString(data.fViewWidget, strValue);
                }
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width"))data.fWidgetAccess->SetValueString(data.fViewWidget, pLeg->NominalWidth);
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height"))data.fWidgetAccess->SetValueString(data.fViewWidget, pLeg->NominalHeight);
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape"))
                {
                    TXString strShape;
                    strShape.itoa(pLeg->Shape);
                    data.fWidgetAccess->SetValueString(data.fViewWidget, strShape);
                }
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length"))data.fWidgetAccess->SetValueReal(data.fViewWidget, pLeg->Length, IShapePaneWidgetAccess::eRealType_Coord);
            }
            else
            {
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_DimensionType"))
                {
                    pLeg->DimensionType = (VWFC::VWObjects::sUserData_JunctionLeg::eLegDimensions) data.fWidgetAccess->GetValueString(data.fViewWidget).atoi();
                }
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Width"))pLeg->NominalWidth = data.fWidgetAccess->GetValueString(data.fViewWidget);
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Height"))pLeg->NominalHeight = data.fWidgetAccess->GetValueString(data.fViewWidget);
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Shape"))
                {
                    pLeg->Shape = (eShape) data.fWidgetAccess->GetValueString(data.fViewWidget).atoi();
                }
                if(fWidgetsContainer.IsWidget(data.fWidgetID, "Leg_Length"))pLeg->Length = data.fWidgetAccess->GetValueReal(data.fViewWidget, IShapePaneWidgetAccess::eRealType_Coord);
                
                // Save user data back into junction and reset it..
                VWMEPJunctionObj JunctionObj(fhObject);
                JunctionObj.SaveLegs(fLegs);
                JunctionObj.ResetObject();
            }

        }

        handled =  true;
    }

 

Edited by Hippocode
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...