Jump to content
Developer Wiki and Function Reference Links ×

Displaying calculations in the OIP


Wizard12

Recommended Posts

I was wondering if anyone has an example of retrieving parameter values from specified PIO parameters and doing a calculation to display as static text on the OIP.  Lets say I have 3 values I need to retrieve, PPanelDepth, PSubstrateThickness, and PLaminateThickness (PIO parameters) and use these in a calculation: PPanelDepth-PSubstrateThickness-PLaminateThickness and then display the result in the OIP, how do I achieve this?  I've seen examples for getting all the parameters and their values and then writing it to a file but no examples of individual field extraction.  I understand that you need to get the handle to the object first to retrieve the field contents but I cant seem to figure out the proper syntax for writing this.  Im guessing GetRField is involved.  Can anyone help with an example?  

Link to comment

I think we need a better understanding of what you are trying to do.

 

If this is for a PIO you are writing, then displaying things in the OIP is as easy as defining them as Parameters.

If this is for a PIO you do not have access to the code for, then about the only option would be to attach a Custom Record Format and write you calculated data to a field and then view that in the Data pane of the OIP

 

I don't think there is a way to get anything to display in the Shape pane of the OIP for a PIO you don't have access to the code.

Link to comment

Hi Pat, thanks for the reply.

 

I have a need to display the calculation of certain parameters in the OIP.  I have a widsget (static text) in the OIP that is to display to the user the stud width based on a calculation of 3 other fields that are named parameters:  Panel Depth, Substrate Thickness and Laminate Thickness.  The result will be the stud width based on the calculation of these 3 fields.

I tried just a straight forward approach but it only calculates what seems to be my default values of my parameters, when I change any of the 3 the resulting calculation does not change:

Maybe my widget type is wrong.

 

            result := vsoInsertWidget (LT, 13, WC2, Num2StrF(PSStudWidthCalc), 0);
            vsoWidgetSetIndLvl (WC2,2);

 

PSStudWidthCalc would be PanelDepth-Substrate Thickness - Laminate Thickness.

 

image.thumb.png.20645c258d94773e0adb711f655b03ea.png

Link to comment

The 2.752" dimension always remains the same regardless of me changing the panel depth.  I know its possible based on seeing that you can write all the parameters including the field contents to a text file but the only examples I can find show every parameter and field value in a list not just obtaining specific desired field values.

Link to comment

So do you actually do the math to get the correct value into PStudWidthCalc somewhere? Does that PStudWidthCalc actually contain the correct value at some point?

 

I don't use widgets, so I can't help much. Perhaps @JBenghiat can comment. I know that usually parameters are only recalculated at the end of the PIO script, so intermittent changes might not be displayed. You might need to use a non-parameter variable for the intermittent display and then store that value back to the parameter at the end of the script.

Link to comment

No, it remains the same calculation.  Those are defaults  for the Plug-in, it seems to be stuck on calculating only those.  Its like nothing calculates in the

5: {kObjOnInitXProperties} or 41: {kObjOnWidgetPrep} sections of the code.  I think its because those sections just deal with the actual widget and its look but not really what the content is.  This is a no brainer in the main part of the script that pertains to the creation of geometry, calculations are straight forward.

Is there a way to store that parameter besides using a record attachment?  Seems like I tried something like that but was not successful.  If you have an idea how to write that and where to put it in the code, that would be awesome.  This Plug-In is for creating Wall Panels for the Exhibit Industry....there are over 340 parameters due to many types of panel configurations and intersections. 

 

Many Thanks Pat, you've helped me a few times in the process of writing this Plug-in.

Link to comment

@Wizard12 

 

I don't think you can do this with widgets, though you might be able to put vsoWidgetSetText code into the kResetEventID section of the code since it will get updated when one of those three field values changes.  The other option would be to use a Static Text parameter, then update it with SetRField at some point in the object creation or reset event.

 

I've attached a very quick and dirty plug-in to demonstrate this.  It takes in two lengths set in the OIP, then sums them and updates both a Static Text parameter and a Static Text widget, and places a text object with the result at the PIO origin point.

 

Let me know if this answers your question or if you have any questions.

Update Object Test.vso

Edited by Jesse Cogswell
  • Like 1
Link to comment

Thanks for the feedback Jesse!  I tried to place the file in my plug ins folder (roaming under app data) but it did not appear through the script editor.  I was able to use NotePad++ to view it and copy it.  It had 2 parameters right?  Length1 and Length2?  I entered those 2 and it compiled.  It did not show anything except the initial dialog but nothing appeared in the OIP so I don't know if it worked.  Based on what your example shows, I will try get it to work.  I'm seeing the vsoWidgetSetText as being one of the key functions here. Thanks for this example, it at least points me in the right direction.

Link to comment

@Wizard12 Did you restart vectorworks after placing the file?  It scans for plug-ins as part of the app start up, so it won't show up new until it starts.  But copying the source code from NotePad++ also works.

 

The parameters are a bit trickier than just Length1 and Length2.  What I tend to do is use the Name field in the parameter editor similar to my normal variable naming conventions (in this case, I did number1 and number2 as Dimension types) and put the "friendly" name in the Alternate Name field.  What's important about this is that VW will use the Name field to refer to the variable in the script itself as well as the record field and will use the Alternate Name field in the Object Info Palette.

 

I also used a third parameter, Name: sumResult, Alternate Name: Sum of Lengths as a Static Text type.  Typically, I will use static text parameters to display extra information in the OIP instead of widgets, mostly because manipulating the OIP with the events coding is a bit messy and poorly documented.

 

The reason it's not showing up for you is that you need to check the "Events-Based" option under the Options tab of the Edit Plug-in Definition dialog.  Any time you start using the events coding, this needs to be selected or it will never reach the Reset coding block to actually draw the objects.

 

Now, more in depth in terms of parameters.  I re-read your original post and it seems that you are having trouble pulling parameters from the OIP.  It's actually REALLY simple, but poorly documented.  The standard syntax is to declare a variable in the main VAR block at the top of the code (I typically name this identically to the parameter Name field in the Edit Plug-in Definition box, but in this strict case I was a bit sloppy.  Originally I was just adding up whole numbers rather than dimensions, but decided to make it dimensions as a better analog to your original question but never updated the Name field).  Then, in your main driver block, initialize the variable with the Name of the parameter with a capital "P" in front.  This tells VW that you are looking at one of the PIO's parameters.

 

As an example, let's say that you had a point plug-in object with a length and width field that would calculate the area and post it in a text box at the point.  You would set up two parameters:

  1. Name: width        Alternate Name: Width      Type: Dimension
  2. Name: height      Alternate Name: Height     Type: Dimension

Code would be as follows:

PROCEDURE Example;

VAR

	width,height:REAL; {This declares the variables your parameters will be saved in}
	area:REAL; {Variable used to store the calculated area}

BEGIN {Main Driver Block}
	width:=Pwidth; {Pulls data from the Width parameter of the OIP}
	height:=Pheight; {Pulls data from the Height parameter of the OIP}

	area:=width*height; {Calculates the area of the two given parameters}

	TextOrigin(0,0); {Sets text origin to insertion point of PIO}
	CreateText(Num2StrF(area)); {Converts REAL variable to a STRING and creates text object}
END;

Run(Example);

You'll notice that this is much simpler than the other code that I posted.  Once you start manipulating the OIP with widgets, you have to start using the Events classes, which then requires a whole lot more code to get set up (the whole kObjOnInitXProperties and such).  This is another reason that I am a big proponent of using Static Text parameters, it's much simpler to code and requires fewer variables and constants.  I pretty much only use widgets when I need to add buttons or double-click functionality to my plug-ins.

 

Let me know if you have any other questions.  Vectorscript is relatively simple, but poorly documented in Vectorworks.  They used to have a whole primer that explained a lot and covered the general syntax in the VW help files, but it was all removed a number of years ago.  The Function Reference is still there, but there are whole chunks that don't have anything by way of example code or even descriptions of what the functions do.

Link to comment

Thanks Jesse.  Oh yes I have that PDF, its old for sure.  The one thing I've noticed is that there isn't a ton of information about widgets, very minimal examples.  Thanks for you help!  So on the first attachment, (.vso) the alternate names are different?  maybe that's why it didn't show up in the OIP.  I can understand that if that's the case, it makes sense since the text widget doesn't have two names.  Doesn't the widget use what would be the 'alternate' name anyway?  that's the problem, my OIP has 340+ parameters so some of which are Procedure run through a subroutine to make the sections for each of the studs parameters.  Since each stud has the same amount of parameters I use variables to place them in collapsible sections but the amount of studs changes based on the panel type which the OIP omits or adds the correct ones per configuration...that was fun to code, not.  The only 2 studs that receive this 'readout' I'm going for are the end studs in which the user can't change the stud width (panel depth determines that), only the widths of the intersection studs are user filled.  So the text display is in only 2 sections for the studs which is run through a subroutine...so I have that little issue to contend with.  I'm going to hit this up in the morning but thanks again for your help!

Link to comment

A couple points to pick up on. 
 

Set/GetRField should always use the parameter name, not the alternate “display” (technically, localized) name. 
 

You should only be adding widgets during the init event. This is where you’re setting the template for the OIP
 

VS doesn’t actually allow you to set the value of a widget field, only the display name of the field, so your only option is to define the calculated field as a static text parameter. 
 

Also not that retrieving data with PParam will return a constant defined at the start of the script, while GetRField will retrieve the stored data. Best practice is to load values into variables and not depend on Re-reading any calculated values. 

Link to comment

The Name vs Alternate Name is a trick from Vectorworks to make for easy localization without needing access to the source code (in case the plug-in is encrypted as a lot of purchased plug-ins are).  Since the code is strictly looking at the Name field, but the end user strictly sees the Alternate Name field, which is also changeable outside of the code, it makes localizing to a different language relatively simple.

 

That being said, I use this as a way to keep track of variables within my own code.  I make the Name of the parameters match my variable naming conventions (camel case, lower case first character), and the Alternate Name "friendlier" for the end user.  Let's use the sumResult parameter from my example code as an example.  It's a lot easier to track a variable named sumResult through my code than remembering a second name.  If I want to change the parameter, it's as easy as typing SetRField(objHd,'PluginName','sumResult',sumResult);  Since the record field name matches my variable name, it's one fewer thing I have to track down.  I don't have to remember if I called the parameter "Sum of Lengths", or "Sum Result", or "Total Length" as in SetRField(objHd,'PluginName','Sum of Lengths',sumResult);

 

And @JBenghiat is quite correct about the PParams.  The top of my main driver block is ALWAYS loading the parameters into variables, very first thing the code does.  I understand if this could be a bummer with 340+ parameters...

Link to comment

JBenghiat thanks for the info, fortunately there are only 2 parameters that need to display a calculation.  How would the syntax look for the GetRField method.  Just a note, I did have to change a bit of Jesse's code for the Widget ID because the common name in the inti event is a changing variable so in the recalculate part of the code I added an extra update.  I structured the code like this to change the wiget Id for placement (these are many more variables than I show under each procedure, just an example to show the structure)

 

    PROCEDURE LeftEndStudPar;
    BEGIN

       PSWidthBool:=True;

       WC2:=4000;   {widget Id}

       LT:=35;            {widget location}

     END;

 

    PROCEDURE RightEndStudPar;
    BEGIN

       PSWidthBool:=True;

       WC2:=4001;

       LT:=109;

     END;

the 5: section is structured like this:

            LeftEndStudPar;
            ParametersInitial;
            RightEndStudPar;
            ParametersInitial;  {procedure to place the widgets and PParameters and the conditions for enable and visibility are in a procedure called ParameterPrep in 41:}

 

In the ParametersInitial Procedure, 

 

        IF(PSWidthBool=TRUE) THEN
        BEGIN
            result := vsoInsertWidget (LT, 13, WC2, 'Test', 0);
            vsoWidgetSetIndLvl (WC2,2);
        END;

there is also a similair stucture for the 41: section

In Jesse's example, the only thing I changed was grabbing the the actual widget ID.

 

3:

        sumLength:=PPanelDepth-PSubstrateThickness-PLaminateThickness;
        sumStr:=Concat('Stud Width:','              ',Num2StrF(sumLength));
        IF GetCustomObjectInfo(objName,objHd,recHd,wallHd) THEN
        SetRField(objHd,'Update Stud Width','sumResult',sumStr);
        vsoWidgetSetText(4001,sumStr);
        vsoWidgetSetText(4002,sumStr);

 

This did work but if there is another method, I'm open to learn more!

 

 

Edited by Wizard12
Link to comment

@Wizard12 sorry, I'm kind of lost by your question. You shouldn't have to deal with widget ID's at all — just use a static text parameter. You can't set the value of a text widget, only its field name.

 

If you have a parameter called StudWidthCalc, you would call:

GetCustomObjectInfo(PIName, PIHan, PIRecHan, PIWallHan);

SetRField( PIHan, PIName, 'StudWidthCalc', calculatedValue);

Link to comment

I see quite a few issues with in the code sample above.

 

Is "SWidthBool" a parameter name? If so, you should not attempt to set PSWidthBool to a value. It is a constant and already defined. If not, I would recommend choosing another variable name so as not to confuse it with the parameter constants.

 

When not in developer mode, kObjOnInitXProperties (event 5) only runs once per session. You should think of this event as describing the plug-in definition to Vectorworks, and as such, it should not depend on any data values. Your widget prep event (kObjOnWidgetPrep = 41) should hide / show and/or enable / disable widgets according to your rules, but the widgets should already exist.

 

As a side note, you're depending a lot on global variables rather than passing arguments. This makes your code harder to read and more likely to introduce errors. For example, ParametersInitial() should be: ParametersInitial( widgetLocation, widgetPosition ), which eliminates the need for separate procedures that redefine global variables.

 

As I've mentioned before, vsoWidgetSetText() only changes the label of the parameter not the value. In your screen shot, you don't have a label for that value, so it appears that you are showing stud thickness twice, which is confusing. This is why you are better off defining a static text parameter and changing the value. As a rule, for VS plug-ins, you should only add button and separator widgets. Every other widget should be tied to a parameter that you've already defined. (I think maybe you're trying to concatenate the label name into the string — that is a very convoluted way of doing this.)

 

In SetRField, the second argument is the name of the record, which matches the name of the plug-in. I'm guessing your PIO isn't called "Update Stud Width," so that call will fail.

  • Like 1
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...