Jump to content
Developer Wiki and Function Reference Links ×

Formatting OIP?


Recommended Posts

The button ID is a unique identifier, like with dialog items. It can be anything, but can’t overlap with the automatically generated IDs of your parameters, which start at 1. To make things easy, I just start my first custom widget at 9000, so I know it’s out of the way. 
 

Appending a widget always puts it at the end of the list. Inserting a widget will place it in with the other widgets, but that is a longer conversation when you are ready. 
 

The last value was reserved for future use but never implemented. I defined a variable called ThisDoesNothing that I use so it’s clear. 
 

I suspect your issue is setting the button ID to 1, which overlaps with your parameter widgets, but in case I need to state the obvious, also make sure you select Event Enabled in the last pane of options in the Plug-in Manager. 

Link to comment

Here's my python templates. I have a pio class, which has all of the constants stored as well as

 class pio:
 	def __init__(self):
        self.PIName = ''
        self.PIHan = 0
        self.PIRecHan  = 0
        self.PIWallHan = 0
        self.x, self.y, self.z, self.rot = 0.0, 0.0, 0.0, 0.0

        boo, self.PIName, self.PIHan, self.PIRecHan, self.PIWallHan = vs.GetCustomObjectInfo()
        if self.PIHan != 0:
            self.rot = vs.GetSymRot(self.PIHan)
            self.x, self.y, self.z = vs.GetSymLoc3D(self.PIHan)

And here is the overall base code

import vs

#vs.SetPref(412, True) #Turns off include caching

# import pydevd
# pydevd.settrace(suspend=False)

from jbld.piolib import pio

PIO = pio()

#===============================================================================
# Initialize and event handler
#===============================================================================
def execute():
    global PIO

    theEvent, eventMessage = None, None
    theEvent, eventMessage = vs.vsoGetEventInfo(theEvent, eventMessage)

    if theEvent == PIO.kObjOnInitXProperties:
        InitPIO()

    elif theEvent == PIO.kObjOnWidgetPrep:
        WidgetPrep()

    elif theEvent == PIO.kObjOnAddState:
        GetStateChange(eventMessage)

    elif theEvent == PIO.kObjOnObjectUIButtonHit:
        ButtonHandler(eventMessage)

    elif theEvent == PIO.kObjOnSpecialEditID:
        SpecialEdit()

    elif theEvent == PIO.kParametricPreference:
        SpecialPreferences()

    elif theEvent == PIO.kResetEventID:
        ResetEventHandler()

#===============================================================================
#  this funciton is executed once and
#  it defines the shape pane of the parametric object
#
#  The shape pane is composed of widgets
#  it is a widget connected to a parameter or it is a button widget
#===============================================================================
def InitPIO():
    # Enable custom shape pane
    ok = vs.SetObjPropVS(PIO.kObjXPropHasUIOverride, True)
    ok = vs.SetObjPropVS(PIO.kObjXHasCustomWidgetVisibilities, True)

    
    vs.SetPrefInt(PIO.kParametricEnableStateEventing, 1 );
    ok = vs.SetObjPropVS(PIO.kObjXPropAcceptStates, True);

    ok = vs.vsoInsertAllParams()
    
    # Insert buttons
    thisDoesNothing = 0
    ok = vs.vsoAppendWidget(PIO.kWidgetButton, PIO.buttonID_1, 'Button_Name', thisDoesNothing)

#==============================================================================
# this function updates the visibility or enable/disable state of the widgets
# note: keep this one fast, it is called often
#==============================================================================
def WidgetPrep():
    # if vs.vsoPrmName2WidgetID('', 'Param_Name', widgID):
    #    vs.vsoWidgetSetVisible( widgID, True )
    # if vs.vsoPrmName2WidgetID('', 'Param_Name', widgID):
    #    vs.vsoWidgetSetEnable( widgID, True )

    # this is very important! this is how the system knows we've handled this
    vs.vsoSetEventResult(PIO.kObjectEventHandled)

#==============================================================================
# Stores regen events to memory
#==============================================================================
def GetStateChange(eventMessage):
    eventMessage = vs.vsoStateAddCurrent(PIO.PIHan, eventMessage)

#==============================================================================
# this function handles button clicks from the shape pane
#==============================================================================
def ButtonHandler(theButton):
    # def ResetAll(h):
    #    vs.ResetObject(h)

    if theButton == PIO.buttonID_1:
        # vs.ForEachObjectInList( ResetAll(), 2, 0, PIO.PIHan )
        vs.AlrtDialog("You pressed a button!")

#===============================================================================
# Handle special edit behavior
#===============================================================================
def SpecialEdit():
    pass

#===============================================================================
# Handle custom preferences dialog
#===============================================================================
def SpecialPreferences():
    if PIO.PIHan == 0:
        PIO.PIHan = vs.GetObject(PIO.PIName)

#==============================================================================
# Main reset event
#==============================================================================
def ResetEventHandler():
    # Parameter => vs.PParameterName
    vs.Locus(0, 0)

 

  • Love 1
Link to comment
9 hours ago, JBenghiat said:

Appending a widget always puts it at the end of the list. Inserting a widget will place it in with the other widgets, but that is a longer conversation when you are ready. 

 

Starting the longer conversation:

 

From experimenting with vsoAddWidget(#,kWidgetType,locName); 

 

I'm assuming that the number in the first argument is the number of the parameter in the definition.  But the values aren't appearing in the OIP.  Is there a different SetObjPropVS that is needed when using only vsoAddWidget?

 

Widget type makes sense.

 

If I use '' as the locName it inserts nothing and a colon. I thought from the function reference that if locName is '' then it uses the alternate name of the parameter?

 

It seems like some changes in the OIP don't take effect until I open a new document.  Is there a way to "reset" the OIP in the current document?

 

Procedure Test;
{Badly Scripted by Michael Klaers.}

CONST
kCR 							=	CHR(13);
kObjOnInitXProperties			=	5;
kObjOnWidgetPrep				=	41;
kObjOnAddState					=	44;
kObjOnObjectUIButtonHit			=	35;
kResetEventID					=	3;
kObjXPropHasUIOverride 			= 	8;
kParametricEnableStateEventing	= 	590;
kObjXPropAcceptStates			=	18;
ButtonID_1						=	9001;
kFieldLongInt     = 1;
kFieldBoolean     = 2;
kFieldReal        = 3;
kFieldText        = 4;
kFieldCalculation = 5;
kFieldHandle      = 6;
kFieldCoordDisp   = 7; {dimension}
kFieldPopUp       = 8;
kFieldRadio       = 9;
kFieldCoordLocX   = 10;	
kFieldCoordLocY   = 11;
kWidgetButton     = 12;
kWidgetStaticText = 13;
kWidgetDisclosure = 14; {not implemented?}

VAR
PIHan, PIRecHan, PIWallHan				: HANDLE;
resultStatus, result					: BOOLEAN;
PIName									: STRING;
eventMessage,theEvent					: LONGINT;


{---------------------------------------------------------------------}
PROCEDURE InitPIO;
BEGIN
	{This tells VW to let the object decide what goes onto the Object Info palette.}
	result:= SetObjPropVS(kObjXPropHasUIOverride, TRUE);
	result := SetObjPropVS(12, TRUE); {kObjXHasCustomWidgetVisibilities}

	SetPrefInt(kParametricEnableStateEventing, 1 );
	result := SetObjPropVS(kObjXPropAcceptStates, TRUE);

	{Now we manually add the "normal" parameters...}
	{One way is to use this single call to add all of the existing parameters.}
	{result:= vsoInsertAllParams;}
	result := vsoAddWidget(1,kFieldCoordDisp,'Blah Width');
	result := vsoAddWidget(2,kFieldCoordDisp,'Blah Height');	
	result := vsoAddWidget(3,kFieldCoordDisp,'Blah Extrusion');	
	result := vsoAddWidget(1,kFieldText,'');	
	
	{Finally, we add the button.}
	result:= vsoAppendWidget(kWidgetButton, ButtonID_1, 'Do Something', 1);
END;
{---------------------------------------------------------------------}
PROCEDURE WidgetPrep;
BEGIN
	vsoSetEventResult( -8 {kObjectEventHandled} );
END;
{---------------------------------------------------------------------}
PROCEDURE GetStateChange;
BEGIN
	eventMessage := vsoStateAddCurrent(PIHan, eventMessage);
END;
{---------------------------------------------------------------------}
PROCEDURE ButtonHandler;
BEGIN
	CASE eventMessage OF
		ButtonID_1:
			BEGIN
			Message('Stop Pressing That Button');
			Sysbeep;
			Wait(3);
			ClrMessage;
			END;
	END;	{CASE}			
END;
{---------------------------------------------------------------------}
PROCEDURE Main;
BEGIN
	BeginXtrd(0,pExtrusion);		
	RectangleN(0, 0, 1, 0, pWidth, pHeight);
	EndXtrd;
			
	{Message(
	'pWidth: ',pWidth,kCR,
	'pHeight: ',pHeight,kCR,
	'pExtrusion: ',pExtrusion
	);
	}		
END;
{---------------------------------------------------------------------}
BEGIN
	resultStatus := GetCustomObjectInfo(PIName, PIHan, PIRecHan, PIWallHan);
	vsoGetEventInfo(theEvent, eventMessage);
	CASE theEvent OF
		{User has single-clicked the object's icon.}
		kObjOnInitXProperties: 
			InitPIO;
		kObjOnWidgetPrep:
			WidgetPrep;
		kObjOnAddState:
			GetStateChange;
		{User has clicked a button in the Object Info palette.}
		kObjOnObjectUIButtonHit:
			ButtonHandler;
		{Object reset has been called.}
		kResetEventID:
			Main;
	END;	{Event case}
END;

RUN(Test);

image.thumb.png.34dc5d068788457c86447795498c8911.png

 

image.thumb.png.fd07730330fbe3427279bac7d6657078.png

Link to comment

So funny you should say that.

 

I've been wondering what the difference is between vsoInsertWidget and vsoAddWidget.  So I tried it out.

 

There must be a setting somewhere I don't quite get yet.  

 

Procedure Test;
{Badly Scripted by Michael Klaers.}

CONST
kCR 							=	CHR(13);
kObjOnInitXProperties			=	5;
kObjOnWidgetPrep				=	41;
kObjOnAddState					=	44;
kObjOnObjectUIButtonHit			=	35;
kResetEventID					=	3;
kObjXPropHasUIOverride 			= 	8;
kParametricEnableStateEventing	= 	590;
kObjXPropAcceptStates			=	18;

ButtonID_1						=	9001;

kWidgetLongInt			= 1;
kWidgetBoolean			= 2;
kWidgetReal				= 3;
kWidgetText				= 4;
kWidgetCalculation		= 5;
kWidgetHandle 			= 6;
kWidgetCoordDisp		= 7;
kWidgetPopUp			= 8;
kWidgetRadio			= 9;
kWidgetCoordLocX		= 10;
kWidgetCoordLocY		= 11;
kWidgetButton			= 12;
kWidgetStaticText		= 13;
kWidgetStaticTextParam	= 14;
kWidgetDisclosure = 14; {not implemented?}
kWidgetDimStdPopUp		= 16;
kWidgetPrecisionPopUp	= 17;
kWidgetClassesPopup		= 18;
kWidgetLayersPopup		= 19;
kWidgetAngleDisp		= 20;
kWidgetAreaDisp			= 21;
kWidgetVolumeDisp		= 22;
kWidgetSeparator		= 100;
kWidgetSubSelection		= 101;
kWidgetBoundPopup		= 102;
kWidgetBoundOffset		= 103;
kWidgetSliderWithEdit	= 104;
kWidgetButtonResourcePopup= 105;
kWidgetBoxPosition		= 106; 
kWidgetResourcePopup	= 107; 
kWidgetSearchablePopup  = 108;
kDeadData				= 0;

VAR
PIHan, PIRecHan, PIWallHan				: HANDLE;
resultStatus, result					: BOOLEAN;
PIName									: STRING;
eventMessage,theEvent					: LONGINT;


{---------------------------------------------------------------------}
PROCEDURE InitPIO;
BEGIN
	{This tells VW to let the object decide what goes onto the Object Info palette.}
	result:= SetObjPropVS(kObjXPropHasUIOverride, TRUE);
	result := SetObjPropVS(12, TRUE); {kObjXHasCustomWidgetVisibilities}

	SetPrefInt(kParametricEnableStateEventing, 1 );
	result := SetObjPropVS(kObjXPropAcceptStates, TRUE);

	{Now we manually add the "normal" parameters...}
	{One way is to use this single call to add all of the existing parameters.}
	{result:= vsoInsertAllParams;}
	result := vsoInsertWidget(1,kWidgetCoordDisp,1,'',kDeadData);
	result := vsoInsertWidget(2,kWidgetCoordDisp,2,'',kDeadData);
	result := vsoInsertWidget(3,kWidgetCoordDisp,3,'',kDeadData);
	vsoWidgetSetIndLvl(3,1);
	result := vsoInsertWidget(4,kWidgetSeparator,0,'',kDeadData);
	result := vsoInsertWidget(5,kWidgetText,4,'',kDeadData);
	

	
	{Finally, we add the button.}
	result:= vsoAppendWidget(kWidgetButton, ButtonID_1, 'Do Something', 1);
END;
{---------------------------------------------------------------------}
PROCEDURE WidgetPrep;
BEGIN
	vsoSetEventResult( -8 {kObjectEventHandled} );
END;
{---------------------------------------------------------------------}
PROCEDURE GetStateChange;
BEGIN
	eventMessage := vsoStateAddCurrent(PIHan, eventMessage);
END;
{---------------------------------------------------------------------}
PROCEDURE ButtonHandler;
BEGIN
	CASE eventMessage OF
		ButtonID_1:
			BEGIN
			Message('Stop Pressing That Button');
			Sysbeep;
			Wait(3);
			ClrMessage;
			END;
	END;	{CASE}			
END;
{---------------------------------------------------------------------}
PROCEDURE Main;
BEGIN
	BeginXtrd(0,pExtrusion);		
	RectangleN(0, 0, 1, 0, pWidth, pHeight);
	EndXtrd;
			
	{Message(
	'pWidth: ',pWidth,kCR,
	'pHeight: ',pHeight,kCR,
	'pExtrusion: ',pExtrusion
	);
	}		
END;
{---------------------------------------------------------------------}
BEGIN
	resultStatus := GetCustomObjectInfo(PIName, PIHan, PIRecHan, PIWallHan);
	vsoGetEventInfo(theEvent, eventMessage);
	CASE theEvent OF
		{User has single-clicked the object's icon.}
		kObjOnInitXProperties: 
			InitPIO;
		kObjOnWidgetPrep:
			WidgetPrep;
		kObjOnAddState:
			GetStateChange;
		{User has clicked a button in the Object Info palette.}
		kObjOnObjectUIButtonHit:
			ButtonHandler;
		{Object reset has been called.}
		kResetEventID:
			Main;
	END;	{Event case}
END;

RUN(Test);

image.thumb.png.6a27ff46eea0bf7d25f74e30dd906f16.png

Link to comment

LocName is the "localized name." It's meant for adapting to language translations, but you can think of it as the display name. This must have a value here. 

 

Here's a few excerpts from a dialog with Sam

 

Quote

Is the “paramID” the param before the button position, after the button positions, the desired button position, or something else? 

 

This is the ID where you want the widget to insert before. I recommend using vsoPrmName2WidgetID to get the location of the item ahead of where you want it and add 1:

result:=vsoPrmName2WidgetID('', 'LXMarkers', widgID);
result:= vsoInsertWidget(widgID+1, kWidgetButton, buttonID_6, GetPluginString( kStr_ButtonMarker ), thisDoesNothing);

 

I do find that inserting widgets can change the widget ID’s that automatically assign to parameters. For that reason, I tend to insert widgets from the bottom up, so that I’m never affecting anything upstream in the index. It’s possible that vsoPrmName2WidgetID() makes this moot, and honestly I haven’t tested in a while, but I definitely found that working from the bottom up prevented a number of headaches. (And this may very well be due to my preference to identify the widget ID after which I want to insert my widget)

 

Quote

 Does this have any effect on the parameter indexes that I reference in the Reset Event.  

 

No — if with vsoStateGetParamChng( PIHan, widgID, prmIndex, oldValue ) you look at prmIndex, as that refers to the parameters, not the widgets. You can think of the parameters as the field indices for the PIO’s data record. The widget ID’s are each item in the OIP, identified by an integer UID.

 

If you act on widgID, then you would need to take those into account.

 

 

Link to comment
  • 2 years later...

Hi everyone. I'm developing a PIO trying to insert all the parameters via script avoiding using the parameters window (NOTE: I still don't understand if it's possible, I hope so). Thanks to your the previous posts everything works fine but can someone explain me with which function I should use to get the current value (string or real) of the widget field to assign to my script variable? There seem to be only pop-up menu commands in the "VS:Function Reference" list. Thank you for the tip.

Link to comment

PIO parameters are "semi-variables" in a Vectorscript.

 

You access them by using the Parmeter Name prefixes with a letter p.

 

So if you have a PIO Parameter named Width, you would use that in your script at pWidth.

 

Two things to remember.

 

1.  The value of the parameter is set at the beginning of the PIO regeneration, so you can't use it as a variable during the regeneration of the PIO.

 

If you have a parameter NumCounter you could use it in a script similar to:

 

For 1 to pNumCounter

 

and it will work fine.

 

But if you try and use it as a real variable like:

 

pNumCounter:=pNumCounter -1

 

It will not as the value is set at the beginning of the PIO regeneration.

 

You can use SetRField to store a new value into the parameter at any time during the regeneration of the PIO, but those stored values can't be used until the next regeneration. GetRField will always return the value present at the beginning of the regeneration.

 

2. Don't name your parameters something that starts with the letter p as you will confuse the compiler.

 

ie. If use Patrick in your script, does that me parameter atrick?  Or should you be using pPatrick?

 

Just don't use it and you will make your life much easier.

 

HTH.  Ask again if you need more information.

Link to comment
11 minutes ago, alberto72 said:

Hi everyone. I'm developing a PIO trying to insert all the parameters via script avoiding using the parameters window (NOTE: I still don't understand if it's possible, I hope so). Thanks to your the previous posts everything works fine but can someone explain me with which function I should use to get the current value (string or real) of the widget field to assign to my script variable? There seem to be only pop-up menu commands in the "VS:Function Reference" list. Thank you for the tip.

 

I suppose it's possible, but not easy. The Parameters window will create a record format and fields to match your parameters. If you are using widgets without associated parameters, then you need to create that record yourself, and use the following workflow:

- On object creation, check if your record format for storing parameter data exists

- If not create the record format

- Attach the record format to the object

- Use state eventing to determine if a widget has changed value

- On widget change, write the new value to your custom record attached to the object

- On object reset, use GetRField to read values

 

You'll also have to provide your own routines for viewing and setting object defaults.

Link to comment
8 minutes ago, Pat Stanford said:

Looks like I completely misread the question

Josh's response is one of those amazing responses that is both complete, if a little cryptic, and the tip of the iceberg.  I would stay away from creating parameters via a script.  If I assume that you are using widgets to display the values of the parameters, you are going to have to maintain the separate record that Josh describes and shuttle values of the record fields back and forth to and from the widgets.  The "to and from" part is not clear to me.  Are you planning on having users enter/choose values by changing the widgets in the OIP, or is the OIP just there to display values.  I'm having a hard time imagining why you want to create the parameters with a script.  Are you trying to create a dynamic OIP that changes its own fields on the fly?  Could you describe how you want to use this PIO such that you need to use a script to create it?

Link to comment
13 hours ago, Sam Jones said:

Josh's response is one of those amazing responses that is both complete, if a little cryptic, and the tip of the iceberg.  I would stay away from creating parameters via a script.  If I assume that you are using widgets to display the values of the parameters, you are going to have to maintain the separate record that Josh describes and shuttle values of the record fields back and forth to and from the widgets.  The "to and from" part is not clear to me.  Are you planning on having users enter/choose values by changing the widgets in the OIP, or is the OIP just there to display values.  I'm having a hard time imagining why you want to create the parameters with a script.  Are you trying to create a dynamic OIP that changes its own fields on the fly?  Could you describe how you want to use this PIO such that you need to use a script to create it?

During PIO development, it is often required to modify OIP by adding, removing, hiding, enabling, or moving fields (via Plugin Manager -> Edit Configuration…) but what I get in the Object Palette Info, is a lot of mess: there’s not immediate update (for me) of the changes to the correct field sequence without restarting the program.

 

This aspect is quite annoying, so I thought that widgets were an advanced method compared to the "Plug-in Manager " method

 

Now, after your valuable advice, I don’t see the advantage of using them.

Noting the immense workflow that Josha has laid out for us, I think I will limit myself to the use of the button widgets (kEventID_OnUIButtonHit = 35) or even custom dialogs.

Link to comment

Widgets aren’t fundamentally different from parameters — behind the scenes  VW creates a widget for each parameter. 
 

You should not have to restart VW to see parameter changes. 
- VW will only update objects in the current document

- The OIP redraws when an object is selected. Usually clearing the selection and then re-selecting the PIO will refresh the OIP
- Occasionally, the OIP needs a kick start for existing objects:

     right-click on the object and select Properties….
     Change a parameter so that the object regenerates.
     Click ok. 
This will usually get the OIP to display your changes. 

  • Like 1
Link to comment

Oh, one more thing:

 

If you're looking for a method of rapid prototyping, take a look at Marionette. You can convert a Marionette network into an object, and any named inputs become parameters. You can even export your Marionette to a python script, though for simple objects it may be a bit bloated.

 

I suppose in theory you could create a PIO completely based on Marionette code, but I haven't experimented enough to know if that's also more complicated than it's worth. http://developer.Vectorworks.net does have some information on coding Marionette nodes.

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