## PPGLayout.Logic

### Introduced

v4.0

### Description

Returns or sets a String value containing the script code associated with the layout in an on-the-fly custom property. This script code contains subroutines to react to events in the property page, which corresponds to the text found in the BeginScript/EndScript section (or equivalent Logic section) of a SPDL file.
The provided string must be a correctly-formed script, written in the language specified in the PPGLayout.Language section. The script is not tested for syntax errors at the time this call is made.
The logic script consists of subroutines implemented in any of the supported Scripting Languages. A routine named "OnInit", if defined, is called when the PPG first loads. To react to a parameter changing, create a routine named "PARAMSCRIPTNAME_OnChanged" with a prefix (optional for on-the-fly custom properties; defaults to the property name for plug-ins). To provide script code that gets executed when a button is pressed, create "BUTTONNAME_OnClicked" (same prefixing rules apply). In all these routines a global instance of the object PPG is available to get context information.
Note: To avoid conflicts with other routines in an on-the-fly custom property, you can specify a prefix using the siUILogicPrefix attribute. This differs from the way that these event handlers are specified for plug-in based custom properties, which by default use the property name as a prefix. For more information on the differences between naming plug-in based and on-the-fly event handlers, see Using Prefixes with Custom Properties and Naming Plug-in Items.
This property makes it possible to still have property page event handling on a custom object even when there is no associated SPDL file. For example it would be possible to read a script file into a string and provide it as the value of this property.
Rather than using this property to embed script code directly in the PPGLayout, it is also possible to specify an external file, using the siUILogicFile attribute. See PPGLayout.SetAttribute.
It is not necessary to set this Property for a CustomProperty that is based on a PluginItem. In that case it is possible to write the event handling callbacks directly in the same script file that implements the Plugin (see PluginRegistrar.RegisterProperty).

### C# Syntax

    // get accessor

    String rtn = PPGLayout.Logic;

    // set accessor

    PPGLayout.Logic = String;

### Examples

#### JScript Example

    /*

    	This script demonstrates how it is possible to create a modal dialog box from

    	scripting to ask a user a question.  It then generates a simple skeleton based

    	on the number of bones and positions requested by the user.

    	Key points of this example:

    	(1) Advantage of Object Model API over SPDL files.

    	Because "for" loops can be used to dynamically add as many parameters

    	are necessary it is easy to handle a variable number of options.  For

    	instance, this example can be changed to support 10 bone skeletons

    	instead of 5 bone skeletons by changing a single variable.

    	(2) Single script file takes care the entire plug-in

    	(3) Logic code can be added to dynamically change the layout in response

    	to the user's actions.  This replaced the need for "spdl logic".

    	(4) JScript's ability to get the source code associated with a function

    	using the toString() property.

    */

    g_maxbones = 5 ;

    Main() ;

    function Main()

    {

    	var oPSet = CreatePSet() ;

    	// We're going to take some of the routines in the script and

    	// inject the code into the PPG layout, using the convenient

    	// toString() method of JScript

    	// Alternatively we could have saved that code as a separate

    	// file

    	var oLayout = oPSet.PPGLayout

    	oLayout.Logic = OnInit.toString() +

    	                BoneNumber_OnChanged.toString() +

    	                CreateLayout.toString() +

    	                AddXYZRow.toString() ;

    	oLayout.Language = "JScript" ;

    	if ( !InspectObj( oPSet, null, null, siModal, false ) ) {

    		CreateBones( oPSet ) ;

    	}

    	// Erase the temporary pset

    	DeleteObj( oPSet ) ;

    }

    function CreatePSet()

    {

    	var oPSet = ActiveSceneRoot.AddProperty( "CustomProperty", false, "Create_Bones_SDK_Example" ) ;

    	// Default number of bones is three

    	oPSet.AddParameter3( "BoneNumber", siInt4, 3 ) ;

    	oPSet.AddParameter3( "origin_x", siDouble, 0 ) ;

    	oPSet.AddParameter3( "origin_y", siDouble, 0 ) ;

    	oPSet.AddParameter3( "origin_z", siDouble, 0 ) ;

    	// Start bone numbering at "1" instead of 0 for usability

    	for ( i = 1 ; i <= g_maxbones ; i++ ) {

    		// We use a simple naming scheme.

    		// e.g. "b4_x" is the "x" axis of bone 4.

    		oPSet.AddParameter3( "b" + i.toString() + "_x", siDouble, i ) ;

    		oPSet.AddParameter3( "b" + i.toString() + "_y", siDouble, i ) ;

    		oPSet.AddParameter3( "b" + i.toString() + "_z", siDouble, i ) ;

    	}

    	// None of the parameters are animatable - we are only using them

    	// temporarily for the UI

    	for ( i = 0 ; i < oPSet.Parameters.Count ; i++ ) {

    		oPSet.Parameters(i).Animatable = false ;

    	}

    	return oPSet ;

    }

    // Do the work based on the values the user has entered in the

    // Custom Property

    function CreateBones( oPSet )

    {

    	// There must always be at least 1 bone

    	oChainRoot = ActiveSceneRoot.Add3DChain(

    		new Array( oPSet.origin_x.Value, oPSet.origin_y.Value, oPSet.origin_z.Value ),

    		new Array( oPSet.b1_x.Value, oPSet.b1_y.Value, oPSet.b1_z.Value )

    	) ;

    	//  Create a variable number of additional bones

    	for ( i = 2 ; i <= oPSet.BoneNumber.Value ; i++ )

    	{

    		strBoneName = "b" + i.toString() ;

    		oChainRoot.AddBone( Array( oPSet.Parameters( strBoneName + "_x" ).Value,

    	                               oPSet.Parameters( strBoneName + "_y" ).Value,

    	                               oPSet.Parameters( strBoneName + "_z" ).Value ) ) ;

    	}

    }

    // Event logic section - this code gets injected as part of the layout

    // Hence it can't rely on any global variables or other functions.

    function OnInit()

    {

    	// Create the initial layout, based on the

    	// default number of bones

    	BoneNumber_OnChanged()

    }

    function BoneNumber_OnChanged()

    {

    	// Redraw the UI, showing only controls

    	// relevant to the number of Bones selected in the drop down

    	CreateLayout(PPG.BoneNumber.Value );

    	PPG.Refresh() ;

    }

    function CreateLayout( in_cntBones )

    {

    	var oLayout = PPG.PPGLayout ;

    	oLayout.Clear() ; // Flush old layout

    	var oItem = oLayout.AddEnumControl(

    	                    "BoneNumber",

    	                    Array( "One", 1,

    	                           "Two", 2,

    	                           "Three", 3,

    	                           "Four", 4,

    	                           "Five", 5 ),

    	                    siControlCombo )

    	oItem.Label = "Number of Bones" ;

    	oLayout.AddGroup( "Bone Positions" );

    		AddXYZRow( oLayout, "Origin", "origin_x", "origin_y", "origin_z" ) ;

    		for ( i = 1 ; i <= in_cntBones ; i++ ) {

    			strOfI = i.toString() ;

    			AddXYZRow(

    			    oLayout,

    			    "Bone " + strOfI,

    			    "b" + strOfI + "_x",

    			    "b" + strOfI + "_y",

    			    "b" + strOfI + "_z" ) ;

    		}

    	oLayout.EndGroup() ;

    }

    // Add a XYZ vector of parameters to the layout

    function AddXYZRow( in_Layout, in_Label, in_xName, in_yName, in_zName )

    {

    	in_Layout.AddGroup( in_Label ) ;

    		in_Layout.AddRow();

    			oItem = in_Layout.AddItem( in_xName ) ;

    			oItem.SetAttribute( siUIValueOnly, true ) ;

    			oItem.SetAttribute( siUINoSlider, true ) ;

    			oItem = in_Layout.AddItem( in_yName ) ;

    			oItem.SetAttribute( siUIValueOnly, true ) ;

    			oItem.SetAttribute( siUINoSlider, true ) ;

    			oItem = in_Layout.AddItem( in_zName ) ;

    			oItem.SetAttribute( siUIValueOnly, true ) ;

    			oItem.SetAttribute( siUINoSlider, true ) ;

    		in_Layout.EndRow() ;

    	in_Layout.EndGroup() ;

    }

### See Also

PPGLayout.Language