scripts (lx_scripts.hpp)

From The Foundry MODO SDK wiki
Jump to: navigation, search
There are security restrictions on this page


Contents

ILxUserValue

This interface provides read-only information about a user value. The type, type name and value are available from the ILxScriptSysService::UserValues().

If the user value has been deleted, all of these methods will fail.

(1) SDK: Declarations
 #define LXu_USERVALUE           "d7fb1eb0-47fe-4dc2-a64f-c8a35a86c51e"

These methods get the value's name and username. If the username is not set, this just returns the name.

The Name() method will always succeed as long as the underlying user value exists. This can be used as a way to test if the object is still valid, or if the user value itself has been deleted out from under the object.

(2) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 Name) (
         LXtObjectID               self,
         const char              **name);
 
         LXxMETHOD(  LxResult,
 UserName) (
         LXtObjectID               self,
         const char              **username);

(3) User Class: UserValue method
         std::string
 Name ()
 {
         const char *name;
         CLxLoc_UserValue::Name (&name);
         return std::string(name);
 }
 
         std::string
 UserName ()
 {
         const char *username;
         CLxLoc_UserValue::UserName (&username);
         return std::string(username);
 }

These return the type (as an LXi_TYPE_ define) and type name of the user value.

(4) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 Type) (
         LXtObjectID               self,
         int                      *type);
 
         LXxMETHOD(  LxResult,
 TypeName) (
         LXtObjectID               self,
         const char              **tname);

(5) User Class: UserValue method
         std::string
 TypeName ()
 {
         const char *tname;
         CLxLoc_UserValue::TypeName (&tname);
         return std::string(tname);
 }

For config user values, this returns LXe_TRUE if a user value is transient, and LXe_FAILS if not. Transient values have a default that is loaded from the config, but the new value is never written to the config -- it is only stored in memory.

(6) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 IsTransient) (
         LXtObjectID               self,
         int                      *isTransient);

These return the value of the user value. GetString() will work on anything, and will return the "raw" string version of the value.

(7) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 GetInt) (
         LXtObjectID               self,
         int                      *val);
 
         LXxMETHOD(  LxResult,
 GetFlt) (
         LXtObjectID               self,
         double                   *val);
 
         LXxMETHOD(  LxResult,
 GetString) (
         LXtObjectID              self,
         char                    *buf,
         unsigned                 len);

This returns the lifespan of the user value.

(8) SDK: Declarations

(9) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 Lifespan) (
         LXtObjectID               self,
         int                      *life);

Get the min/max values. There are separate functions for float and int types, as well as flags indiciating if min/max is set.

(10) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 FloatRange) (
         LXtObjectID               self,
         int                      *hasMin,
         double                   *min,
         int                      *hasMax,
         double                   *max);
         LXxMETHOD(  LxResult,
 IntRange) (
         LXtObjectID               self,
         int                      *hasMin,
         int                      *min,
         int                      *hasMax,
         int                      *max);

Get the list and their names as string, similar to the one passed to user.def. The ArgumentType used to get usernames from the config is also available. These methods fail with NOTAVAILABLE for non-integer types, and fail with NOTFOUND if they are not set.

(11) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 List) (
         LXtObjectID               self,
         const char              **list);
 
         LXxMETHOD(  LxResult,
 ListNames) (
         LXtObjectID               self,
         const char              **listNames);
 
         LXxMETHOD(  LxResult,
 ArgType) (
         LXtObjectID               self,
         const char              **argType);

(12) User Class: UserValue method
         std::string
 List ()
 {
         const char *list;
         CLxLoc_UserValue::List (&list);
         return std::string(list);
 }
 
         std::string
 ListNames ()
 {
         const char *listNames;
         CLxLoc_UserValue::ListNames (&listNames);
         return std::string(listNames);
 }
 
         std::string
 ArgType ()
 {
         const char *argType;
         CLxLoc_UserValue::ArgType (&argType);
         return std::string(argType);
 }

Get the action (command string) executed when the user value changes. Returns NOTFOUND if no action is set.

(13) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 Action) (
         LXtObjectID               self,
         const char              **action);

(14) User Class: UserValue method
         std::string
 Action ()
 {
         const char *action;
         CLxLoc_UserValue::Action (&action);
         return std::string(action);
 }

This returns LXe_TRUE if an action is to be deferred after refiring has completed, and LXe_FALSE if not. It returns NOTFOUND if no action is set.

(15) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 DeferAction) (
         LXtObjectID               self);

Get the dialog username string for the user value. Returns NOTFOUND if none is set.

(16) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 DialogUserName) (
         LXtObjectID               self,
         const char              **username);

(17) User Class: UserValue method
         std::string
 DialogUserName ()
 {
         const char *username;
         CLxLoc_UserValue::DialogUserName (&username);
         return std::string(username);
 }

Get the value preset cookie string for the user value. Returns NOTFOUND if no action is set.

(18) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 ValuePresetCookie) (
         LXtObjectID               self,
         const char              **cookie);

(19) User Class: UserValue method
         std::string
 ValuePresetCookie ()
 {
         const char *cookie;
         CLxLoc_UserValue::ValuePresetCookie (&cookie);
         return std::string(cookie);
 }

Get the command whose enable state is also applied to this user value. Returns NOTFOUND if none is set.

(20) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 EnableCommand) (
         LXtObjectID               self,
         const char              **command);

(21) User Class: UserValue method
         std::string
 EnableCommand ()
 {
         const char *command;
         CLxLoc_UserValue::EnableCommand (&command);
         return std::string(command);
 }

Get the notifier that causes the user value's control to be updated in the interface. Returns NOTFOUND if none is set.

(22) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 Notifier) (
         LXtObjectID               self,
         const char              **notifier);

(23) User Class: UserValue method
         std::string
 Notifier ()
 {
         const char *notifier;
         CLxLoc_UserValue::Notifier (&notifier);
         return std::string(notifier);
 }

Get the default value as an ILxValue. This fails with NOTFOUND if none is set.

(24) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 DefaultValue) (
         LXtObjectID               self,
         void                    **ppvObj);

Get if changing the user value via user.value be treated as an undoable UI command instead of an undoable model command. UI commands exist in the undo stack only until a model command is executed, while model commands persist in the stack. UI mode is useful when creating preferences, while model mode is useful when the user value is used to directly affect the scene itself, usually by performing an assocated action when the value changes. This returns LXe_TRUE for UI style behavior, and LXe_FALSE for model style behaviors.

(25) SDK: ILxUserValue interface
         LXxMETHOD(  LxResult,
 AsUI) (
         LXtObjectID               self);

Empty UserValue Python user class.

(26) PY: UserValue method
 pass

ILxSessionListener

The session listener provides information about application startup and shutdown. A "session" is defined as the time the app is running, from when it starts to when it exits.

(27) SDK: Declarations
 #define LXu_SESSIONLISTENER     "b5cb3afe-3f0c-4498-b530-1726811b1401"
 #define LXa_SESSIONLISTENER     "sessionlistener"

This is called just before the first window (usually the main window) is opened, which generally means that the app is nearing final readiness. This is not sent in headless mode for obvious reasons.

(28) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 FirstWindowOpening) (
         LXtObjectID               self);

This is called just before the startup commands are executed. This can be used to execute other startup commands from code, for example, or to query commands.

(29) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 BeforeStartupCommands) (
         LXtObjectID               self);

This is called after any startup comamnds have executed, and just before the application main loop starts, and indicates that the application is fully initialized and ready.

(30) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 SystemReady) (
         LXtObjectID               self);

This is called when the app's UI is told to quit, usually because the user tried to close the main window or chose Quit from the system menu. Most importantly, the main window is still open at this time, and the listener can open dialogs and is able to abort the quit by returning LXe_FALSE.

Remember that you may not be the only session listener, that all listeners will get this event, and that the abort state won't be read until all listeners have returned (this is jsut how listeners work). Before opening a dialog or doing any other quit tests, you should check the value of quitWasAborted; if ture, you may simply want to exit early because another listeener has decided that we're not going to quit after all.

As the name implies, this method is only sent from the UI, and never from headless. If you need to save critical state, yous hould do so from ShuttingDown().

(31) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 CheckQuitUI) (
         LXtObjectID               self,
         int                       quitWasAborted);

If no listeners have aborted the quit, this method is called to indicate that we really are going to exit the app. At this point the main window is still open, so if you want to save something with a progress bar or the possibility of opening an error dialog, you can. However, you will not be able to keep the app from quitting.

Once again, this is not sent from headless mode.

(32) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 QuittingUI) (
         LXtObjectID               self);

This is called just after the last window (usually the main window) has closed, indicating that the application is about to shut down. This is not sent in headless mode for obvious reasons.

(33) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 LastWindowClosed) (
         LXtObjectID               self);

After all windows have been closed (or in headless, if we're about to quit), this is called to indicate that we're going to start shutting down the remaining systems and exit the app. This is a good time to store any other state you may want to persist between sessions.

(34) SDK: ILxSessionListener interface
         LXxMETHOD(  LxResult,
 ShuttingDown) (
         LXtObjectID               self);

C++ user class.

(35) User Class: SessionListener method

Empty SessionListener Python user class.

(36) PY: SessionListener method
 pass

ILxUserValueListener

The user value listener alerts clients when a user value has changed. It also has methods that are called at various points in the startup sequence so that user values can be cached after startup or actions can be taken during the startup process.

(37) SDK: Declarations
 #define LXu_USERVALUELISTENER   "13a85a48-06aa-4a75-9e73-066ee3cb761f"

This is called after a new user value is added. The object provided has an ILxUserValue interface. Since the value was just added, the obejct is only immediately useful for getting its name, as everything else will be defaults.

(38) SDK: ILxUserValueListener interface
         LXxMETHOD(  LxResult,
 Added) (
         LXtObjectID               self,
         LXtObjectID               userValue);

This is called just after an existing user value is deleted. Since the object was just deleted, only the name is provided.

(39) SDK: ILxUserValueListener interface
         LXxMETHOD(  LxResult,
 Deleted) (
         LXtObjectID               self,
         const char               *name);

This is called when the definition (one of the properties) of a user value has changed. The object provided has an ILxUserValue interface.

(40) SDK: ILxUserValueListener interface
         LXxMETHOD(  LxResult,
 DefChanged) (
         LXtObjectID               self,
         LXtObjectID               userValue);

This is called when the user value's value changes. It is also called for all user values on startup, thus ensuring that clients that only listen for this event can get useful default values. The object provided has an ILxUserValue interface.

(41) SDK: ILxUserValueListener interface
         LXxMETHOD(  LxResult,
 ValueChanged) (
         LXtObjectID               self,
         LXtObjectID               userValue);

C++ user class.

(42) User Class: UserValueListener method

Empty UserValueListener Python user class.

(43) PY: UserValueListener method
 pass

Example Usage

A common way to use user values is for preferences. The user.value command is put into a form in the prefs. The plug-in registers a listener from its constructor. Note that it is important to check the SpawnForTagsOnly() method for true before registering the listener, as the system won't be ready until then and may crash.

(44) SDK: Setting Up The Listener From The Constructor
 CLxUser_HostService              hostSrv;
 
 // Make sure we're really ready to be spawned
 if( hostSrv.SpawnForTagsOnly() == LXe_TRUE )
         return;
 
 // Add our listener
 uvl_listener = pF->uvl.Spawn ();
 lisSrv.AddListener (uvl_listener) ;

User values are not thread safe. It is a good idea to cache the value for future use, even if you don't think you'll be used in a thread (for example, all preset servers and image loaders may be used from threads).

You only have to implement ILxUserValueListener::ValueChanged(). This is called on startup (or if you registered after startup, soon after registration) for every user value found, and will be called any time the value changes. You can use the provided ILxUserValue to get the current value, among other properties, which you should then cache in a global for later user to avoid the overhead of calling this method, and any issues related to thread safety.

Script Aliases

To simplify the use of scripts in kits, we support script aliases. This allows a script hash (aka the path to a script on disk) to be aliased to an arbitrary string.

Script aliases are defined solely from within configs, usually by the script's developer. The alias may include path aliases, and may included any ASCII characters, although it is important to note that it is not a translatable string.

When used in kits, the simple form can be used when the script is in the kit's directory:

<hash type="ScriptAlias" key="aliasedScriptName">myScript.pl</p>

When defined outside of a kit, the full path to the script must be used.

<hash type="ScriptAlias" key="aliasedScriptName">pathAlias:dir/myScript.pl</p> <hash type="ScriptAlias" key="aliasedScriptName">c:\dir\myScript.pl</p>

Once defined, the script alias can be used in place of the script's path at any time to lookup and/or execute the script, including in commands like script.run, script.implicit, and the @ syntax.

This utility can be used by clients to resolve a script alias to its full path. The path returned will always be a valid string, returning a the resolved path if possible, and returning the alias otherwise. This allows you to just pass in any script path or a known alias and get back a usable path, even though the function will fail if the alias cannot be resolved.

This returns LXe_NOTFOUND if the alias does not exist, in which case the alias passed in is returned. This returns LXe_FAILED if the alias exists, but could not be resolved into an absolute path. In this case, the aliased path will be returned instead of the alias name or the resolved path.

Just to clarify: - LXe_FAILED returns the alias: aliasedScriptName - LXe_NOTFOUND returns the alias path: pathAlias:dir/myScript.pl - LXE_OK returns the resolved absolute path: <path that 'pathAlias:' points to>/dir/myScript.pl

(45) SDK: ILxScriptSysService interface
         LXxMETHOD(  LxResult,
 ResolveAlias) (
         LXtObjectID               self,
         const char               *alias,
         const char              **path);

Nexus 10.1

This provides a high-level way to look up a scriopt by path. It loops though all of the script servers and returns the ILxScriptManager that found the script, and an ILxScript representing the script itself. The write and tryAsUsername arguments work identically to those on the ILxScriptManager::Lookup() method.

This also provides a caching mechanism based on the script's path, making it efficient to look up a script without having to hit the disk each time for disk-based scripts.

(46) SDK: ILxScriptSysService interface
         LXxMETHOD(  LxResult,
 LookupScript) (
         LXtObjectID               self,
         const char               *hash,
         int                       write,
         int                       tryAsUsername,
         void                    **service,
         void                    **script);

Empty scriptsys service Python user class.

(47) PY: ScriptSysService method
 pass

Script Manager

The script manager is provided as a global. It is used to obtain information about a particular scripting subsystem. Each type of script has a matching script manager, although one manager can handle multiple script types. As well as providing a list of available scripts known to the manager, they also include the interpreter used to execute said scripts.

(48) SDK: Declarations
 #define LXu_SCRIPTMANAGER       "3699E7C5-44B8-4e07-B8CA-E26899CD7B3B"
 #define LXa_SCRIPTMANAGER       "scriptservice"

This returns the name of the script manager, which should be the name of the plug-in itself, or else the system will get very confused. Script manager names should have the format "name.scriptservice", as the .scriptservice part is automatically skipped during lookup for convenience.

(49) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 Name) (
         LXtObjectID              self,
         const char             **name);

Script managers can return a number of flags describing how the manager operates.

(50) SDK: Declarations
 #define LXfSCRIPTSRV_CREATE             0x0001
 #define LXfSCRIPTSRV_REMOVE             0x0002
 #define LXfSCRIPTSRV_LINE_ACTION        0x0003

CREATE
REMOVE
These should be set if the Script Editor can create or delete scripts.
LINE_ACTION
This is set if an operation is defined for single lines in a script. For example, double-clicking on a macro line to execute that command.

(51) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 Flags) (
         LXtObjectID              self,
         int                     *flags);

These functions allow the list of available scripts to be walked. When getting a script from the manager, the write flag determines if the script is read-only or read/write. This is just a hint; if the script cannot be modified and the write flag is set, the function should fail with LXe_SCRIPT_READONLY.

(52) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 Count) (
         LXtObjectID              self,
         unsigned int            *count);

(53) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 ByIndex) (
         LXtObjectID              self,
         unsigned int             index,
         void                   **ppvObj,
         int                      write);

This looks up a script by its hash. Note the lookup may succeed even if it is not in the script list, as the manager may try to load the script off disk, for example. If tryAsUserName is true, the hash will be looked up as a username if it cannot be found as a hash.

It is important to note that the hash may not be what you expect. For example, if you normally expect a path to a file, you should be able to handle arbitrary cases like config hashes (say, "872345659345:macro") and not try to pass them to file system functions that might hit the network and create long delays.

Similarly, if you recognize the hash as your own but cannot find the contents, you should return LXe_SCRIPT_RECOGNIZED_INVALID. This keeps other servers from having to scan servers that only you recognize.

(54) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 Lookup) (
         LXtObjectID              self,
         const char              *hash,
         void                   **ppvObj,
         int                      write,
         int                      tryAsUserName);

Scripts can be read-only (for example, if the perl script is read-only on disk, or the config the macro is in is imported). This function tells if the script can be instanced as read/write or just read-only.

Since the intention is to see if the script can be instanced as read/write before you have a script ID, this takes a hash or index as its args; the index is checked if the hash is NULL.

(55) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 ReadWrite) (
         LXtObjectID              self,
         const char              *hash,
         int                      index);

A new script for this manager can be created and filled in by the client.

(56) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 New) (
         LXtObjectID              self,
         const char              *name,
         void                   **ppvObj);

An existing script can be removed from the system. This only removes the script; it does not necessarily delete it from disk.

(57) SDK: ILxScriptManager interface
         LXxMETHOD(  LxResult,
 Remove) (
         LXtObjectID              self,
         LXtObjectID              script);

Scripts can be validated to ensure that they are supported by the interpreter and to check that they are free of errors before execution. The interpreter should return SCRIPT_UNKNOWN if the script is not supported by the interpreter, and SCRIPT_ERROR if there is a problem parsing the script. SCRIPT_WARNING can be returned if there are only warnings, but since this is an OK code, the script can still be considered mostly valid and thus executable.

(58) SDK: ILxScriptManager interface
         LXxMETHOD (LxResult,
 Validate) (
         LXtObjectID              self,
         LXtObjectID              script,
         LXtObjectID              msg);

A script can be executed with this function. The command services global can be used to query and execute commands as needed. Commend execution flags are also provided, which can be used to decide how to interact with the user for warnings, etc. A list of optional arguments can also be provided as a string, or be NULL.

(59) SDK: ILxScriptManager interface
         LXxMETHOD (LxResult,
 Run) (
         LXtObjectID              self,
         LXtObjectID              script,
         int                      execFlags,
         const char              *args,
         LXtObjectID              msg);

Text Script Interpreter

Many scripts simply involve parsing text files and interpreting the lines in turn. Rather than forcing the creating of a completely new manager each time, a simple text script interpreter can be created.

The script system automatically handles loading of text files from disc, and provides search paths for scripts and so on. All the interpreter needs to do is confirm that it actually can deal with this kind of script and execute it.

(60) SDK: Declarations
 #define LXu_TEXTSCRIPTINTERPRETER       "D612FFCE-4B94-4823-A0A7-CC7CA2DDC3D6"
 #define LXa_TEXTSCRIPTINTERPRETER       "textscriptinterpreter"

An initial validation of the file is performed to figure out what interpreters support which files. The interpreter is provided with an ILxScriptID and the first line of the script, which allows for a common first-line check or a more complete check of the script's contents via GetBuffer(). The hash of the script is the path of the file on disk, and can be used to check the extension if desired. The interpreter should return LXe_OK if it can deal with this script, and LXe_SCRIPT_UNKNOWN if it cannot.

This method should be quick, since it may be called often. Simply check the file type here; don't test the script for errors or anything like that.

(61) SDK: ILxTextScriptInterpreter interface
         LXxMETHOD(  LxResult,
 ValidateFileType) (
         LXtObjectID              self,
         LXtObjectID              script,
         const char              *firstLine);

Before execution of a script, this function is called to ensure that the script is properly formatted for execution by this interpreter. SCRIPT_ERROR can be returned on failer, and SCRIPT_WARNING if the script can be executed, but there may be problems with it. The ILxMessageID can be used to report specific errors.

(62) SDK: ILxTextScriptInterpreter interface
         LXxMETHOD(  LxResult,
 Validate) (
         LXtObjectID              self,
         LXtObjectID              script,
         LXtObjectID              msg);

A script can be executed with this function. The command services global can be used to query and execute commands as needed. Commend execution flags are also provided, which can be used to decide how to interact with the user for warnings, etc. A list of optional arguments can also be provided as a string, or be NULL. The ILxMessageID can be used to report specific errors.

(63) SDK: ILxTextScriptInterpreter interface
         LXxMETHOD (LxResult,
 Run) (
         LXtObjectID              self,
         LXtObjectID              script,
         int                      execFlags,
         const char              *args,
         LXtObjectID              msg);

Empty TextScriptInterpreter Python user class.

(64) PY: TextScriptInterpreter method
 pass

To clients, the text interpreter is wrapped up as an ILxScriptManager, so there is no need for internal wrappers for these functions.

Script

Scripts provide an ILxScript interface. This allows clients to browse the contents of a script for display to the user, for example. For example, the attribute editor displays script contents

(65) SDK: Declarations
 #define LXu_SCRIPT              "33C03F3F-A692-4bf4-8AB4-C5A95CA7930C"
 #define LXa_SCRIPT              "script"

Scripts have a hash used for lookup. For macros, it's just the hash in the config; for scripts in files, it might be the filename.

(66) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 Hash) (
         LXtObjectID              self,
         const char             **hash);

Scripts may have a username and description.

(67) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 UserName) (
         LXtObjectID              self,
         const char             **userName);

(68) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 SetUserName) (
         LXtObjectID              self,
         const char              *userName);

(69) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 Desc) (
         LXtObjectID              self,
         const char             **desc);

(70) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 SetDesc) (
         LXtObjectID              self,
         const char              *desc);

This returns a semicolon-delimited list of icon resources. If not implemented, the hash of the script is used.

(71) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 Icon) (
         LXtObjectID              self,
         const char             **icon);

The script manager can also return a help key, which will be looked up in the HelpURLs config entries. An argument string can also be provided for more specific lookups.

(72) SDK: ILxScript interface
         LXxMETHOD(  LxResult,
 HelpKey) (
         LXtObjectID              self,
         const char              *args,
         const char             **key);

The script's type is obtained by asking for its manager.

(73) SDK: ILxScript interface
         LXxMETHOD (LxResult,
 Manager) (
         LXtObjectID              self,
         void                   **ppvObj);

This gets the full text of the script as one large buffer, read-only NUL-terminated text buffer. The length of the buffer is also returned.

(74) SDK: ILxScript interface
         LXxMETHOD (LxResult,
 GetBuffer) (
         LXtObjectID              self,
         const char             **buffer,
         unsigned int            *bufferLength);

This replaces the existing script's contents with a new one. The buffer should be NUL-terminated, and the buffer length should include the NUL.

(75) SDK: ILxScript interface
         LXxMETHOD (LxResult,
 SetBuffer) (
         LXtObjectID              self,
         const char              *buffer,
         unsigned int             bufferLength);

Empty Script Python user class.

(76) PY: Script method
 pass

Platform Service

The platform service provides information about the application and OS.

(77) SDK: Declarations
 #define LXu_PLATFORMSERVICE     "B9596D64-8CB3-4943-8415-7EDF527AE513"
 #define LXa_PLATFORMSERVICE     "platformservice"

(78) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 ScriptQuery) (
         LXtObjectID              self,
         void                   **ppvObj);

Get the user the app is licensed to. If not licensed, this fails.

(79) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 LicensedTo) (
         LXtObjectID               self,
         const char              **licensee);

(80) User Service Class: PlatformService method
         std::string
 LicensedTo ()
 {
         const char *licensee;
         CLxLoc_PlatformService::LicensedTo (&licensee);
         return std::string(licensee);
 }

Get the number of days left until the key expires, or -1 if the key is permanent.

(81) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 ExpiresIn) (
         LXtObjectID              self,
         int                     *daysLeft);

Get the serial number of this key.

(82) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 SerialNumber) (
         LXtObjectID               self,
         const char              **serial);

(83) User Service Class: PlatformService method
         std::string
 SerialNumber ()
 {
         const char *serial;
         CLxLoc_PlatformService::SerialNumber (&serial);
         return std::string(serial);
 }

Get the number of licenses this key works with.

(84) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 NumLicenses) (
         LXtObjectID               self,
         int                      *licenses);

Get the application name.

(85) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 AppName) (
         LXtObjectID               self,
         const char              **name);

(86) User Service Class: PlatformService method
         std::string
 AppName ()
 {
         const char *appName;
         CLxLoc_PlatformService::AppName (&appName);
         return std::string(appName);
 }

Get the version and build numbers of the application.

(87) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 AppVersion) (
         LXtObjectID              self,
         int                     *version);
 
         LXxMETHOD(  LxResult,
 AppBuild) (
         LXtObjectID              self,
         int                     *build);

This returns LXe_TRUE if the app is running in headless mode, and LXe_FALSE if not.

(88) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 IsHeadless) (
         LXtObjectID              self);

(89) User Service Class: PlatformService method
         bool
 IsHeadless ()
 {
         return (CLxLoc_PlatformService::IsHeadless () == LXe_TRUE);
 }

Get the OS type, OS name and OS version string.

(90) SDK: Declarations
 #define LXiOSTYPE_UNKNOWN   0
     #define LXiOSTYPE_WIN32         1
     #define LXiOSTYPE_MACOSX        2
 #define     LXiOSTYPE_LINUX         3

(91) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 OSType) (
         LXtObjectID              self,
         int                     *type);

(92) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 OSName) (
         LXtObjectID               self,
         const char              **name);

(93) User Service Class: PlatformService method
         std::string
 OSName ()
 {
         const char *osName;
         CLxLoc_PlatformService::OSName (&osName);
         return std::string(osName);
 }

(94) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 OSVersion) (
         LXtObjectID               self,
         const char              **version);

(95) User Service Class: PlatformService method
         std::string
 OSVersion ()
 {
         const char *osVersion;
         CLxLoc_PlatformService::OSVersion (&osVersion);
         return std::string(osVersion);
 }

Walk the list of paths.

(96) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 PathCount) (
         LXtObjectID               self,
         int                      *count);
 
         LXxMETHOD(  LxResult,
 PathByIndex) (
         LXtObjectID               self,
         int                       index,
         const char              **path);

(97) User Service Class: PlatformService method
         const char *
 GetPath (
         int                      index)
 {
         const char              *path = 0;
 
         PathByIndex (index, &path);
         return path;
 }

This returns the internal name of the path, or NULL if the path doesn't have one.

(98) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 PathNameByIndex) (
         LXtObjectID               self,
         int                       index,
         const char              **name);

(99) User Service Class: PlatformService method
         const char *
 GetPathName (
         int                      index)
 {
         const char              *path = 0;
 
         PathNameByIndex (index, &path);
         return path;
 }

Walk the list of imported resource paths.

(100) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 ImportPathCount) (
         LXtObjectID               self,
         int                      *index);
 
         LXxMETHOD(  LxResult,
 ImportPathByIndex) (
         LXtObjectID               self,
         int                       index,
         const char              **path);

(101) User Service Class: PlatformService method
         const char *
 GetImportPath (
         int                      index)
 {
         const char              *path = NULL;
 
         ImportPathByIndex (index, &path);
         return path;
 }

This returns true if the application (but not necessarily the platform) is 64 bit, and false if it's 32 bit.

(102) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 IsApp64Bit) (
         LXtObjectID               self);

(103) User Service Class: PlatformService method
         bool
 IsApp64Bit ()
 {
         return (CLxLoc_PlatformService::IsApp64Bit () == LXe_TRUE);
 }

(104) SDK: Declarations
 #define                  LXiUSERIDLE_ALWAYS                     0x0000
 
 #define                  LXfUSERIDLE_APP_MUST_BE_ACTIVE         0x1000
 
 #define                  LXfUSERIDLE_MOUSE_BUTTONS_UP           0x0001  // All mouse buttons must be up
 #define                  LXfUSERIDLE_KEYS_UP                    0x0002  // All non-modifier keys must be up
 #define                  LXfUSERIDLE_MODIFIER_KEYS_UP           0x0004  // All modifier keys must be up
 #define                  LXfUSERIDLE_NO_DIALOGS_OPEN            0x0008  // No modal windows may be open, including system dialogs
 #define                  LXfUSERIDLE_NO_POPS_OPEN               0x0010  // No popups/popovers may be open (except for tooltips)
 #define                  LXfUSERIDLE_CMD_STACK_EMPTY            0x0020  // The command stack must be empty
 #define                  LXfUSERIDLE_NO_SUB_INPUT_LOOP          0x0040  // Cannot be in a secondary input loop; meaning, we must be in the root-level input loop or no input loop at all
 #define                  LXfUSERIDLE_EDIT_FIELDS_UNFOCUSED      0x0080  // Edit field cannot have focus
 
 #define                  USERIDLEf_ALL_IDLE                     0x0FFF  // Everything except APP_MUST_BE_ACTIVE

This arms a user idle action, preferably only once until it has been fired, after which you can arm it again if necessary.

(105) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 DoWhenUserIsIdle) (
         LXtObjectID               self,
         LXtObjectID               visitor,
         int                       flags);

This can be used to remove a pending user idle action. It will do nothing if the idle action isn't armed. Note that flags and the vistor pointer must be exactly the same as the one passed to DoWhenUserIsIdle(), or else it will not be found and the action will remain armed.

Note that when doing this from Python, you must pass the exact same visitor COM object (not Python object). This is also necessary when removing listeners and canceling timers, as discussed here: http://modo.sdk.thefoundry.co.uk/wiki/FAQ#Q:_How_do_I_remove_a_listener_object_in_Python.3F

(106) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 CancelDoWhenUserIsIdle) (
         LXtObjectID               self,
         LXtObjectID               visitor,
         int                       flags);

This simply returns if the user is currently idle. It can be useful at times, but generally you always want to perform your idle actions from DoWhenUserIsIdle().

(107) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 IsUserIdle) (
         LXtObjectID               self);

Another useful feature is to be able to know when the app has become active or inactive. This returns LXe_TRUE if the app is currently active.

(108) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 IsAppActive) (
         LXtObjectID               self);

Session Stage (Nexus 801)

The current session stage can be read with this method, indicating the status of the application.

(109) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 SessionStage) (
         LXtObjectID               self,
         int                      *stage);

The stage can be one of the following:

(110) SDK: Declarations

NOT_READY
The system is in the very early startup phase, and is not yet ready to be accessed.
STARTUP_COMMANDS
Startup commands are or have just executed, and the system is almost completely up and running.
SYSTEM_READY
The main event loop is running, and the application is fully started.
SHUTTING_DOWN
The main event loop has stopped, and the applicatin is shutting down.

You can register an ILxSessionListener to be notified when the stage changes.

The application username may be different from the internal name returned by AppName(). Usually this is farily minor, such as the case of the name.

(111) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 AppUsername) (
         LXtObjectID               self,
         const char              **name);

(112) User Service Class: PlatformService method
         std::string
 AppUsername ()
 {
         const char *appName;
         CLxLoc_PlatformService::AppUsername (&appName);
         return std::string(appName);
 }

Timers (Nexus 901+)

Timers execute after a pre-determiend number of milliseconds. A timer executes only once, but you can re-arm it when it expires if you want. The most common use of timers is to check files for changes or trigger periodic refreshes of part of the UI.

Note that timers can trigger at arbitrary and unsafe times, such as in the middle of rendering or while saving a file. You should never execute a command from a timer, for exmaple, but rather arm a user idle action (and even then executing commands is a bit iffy, since now you're adding something to the command history or undo list that the user didn't do directly, but sometimes it is necessary).

If idleFlags are LXiUSERIDLE_ALWAYS, then the timer's visitor is called as soon as the timer expires. Otherwise, the action is deferred until user idle state matches the flags.

(113) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 TimerStart) (
         LXtObjectID               self,
         LXtObjectID               visitor,
         int                       milliseconds,
         int                       idleFlags);

A currently-running timer can be canceled with this function. The visitor and flags must match what the timer was armed with.

Note that when doing this from Python, you must pass the exact same visitor COM object (not Python object). This is also necessary when removing listeners and canceling user idle actions, as discussed here: http://modo.sdk.thefoundry.co.uk/wiki/FAQ#Q:_How_do_I_remove_a_listener_object_in_Python.3F

(114) SDK: ILxPlatformService interface
         LXxMETHOD(  LxResult,
 TimerCancel) (
         LXtObjectID               self,
         LXtObjectID               visitor,
         int                       idleFlags);

Empty platform service Python user class.

(115) PY: PlatformService method
 pass

Appplication Activation Listener

Clients can be notified when the application gets or loses focus by listening to the ILxAppActiveListener port. A common use of this is to check to see if any files have changed since the user last left the app, or to pause some networking or other interprocess communication until the app gains/loses focus again.

(116) SDK: Declarations
 #define LXu_APPACTIVELISTENER   "7c35c2c0-8116-43f7-8277-dd521d1bd6a8"
 #define LXa_APPACTIVELISTENER   "appactivelistener"

This is called with true when the app becomes active, and false when it becomes inactive. User idle actions can be armed from this method to execute commands as needed.

(117) SDK: ILxAppActiveListener interface
         LXxMETHOD(  LxResult,
 IsNowActive) (
         LXtObjectID               self,
         int                       isActive);

Empty AppActiveListener Python user class.

(118) PY: AppActiveListener method
 pass

Line Interpreter

A line interpreter is a persistent server that interprets lines of text as interactive commands. The simplest (built-in) interpreter is one that treats each line of input as a command or query and generates output. More complex interpreters could process input using a scripting language.

(119) SDK: Declarations
 #define LXu_LINEINTERPRETER     "8F7DF2BE-69A2-4E1C-A4E9-CB3BC3D534D5"
 #define LXa_LINEINTERPRETER     "lineinterpreter"

(120) SDK: ILxLineInterpreter interface
         LXxMETHOD(  unsigned,
 Flags) (
         LXtObjectID              self);

(121) SDK: Declarations
 #define LXfLINT_NOPROMPT                0x01
 #define LXfLINT_NORESULT                0x02
 #define LXfLINT_NOCOOKING               0x04
 #define LXfLINT_NOUNDOS                 0x08

NOPROMPT
The user-provided or default prompt is used, and the server does not define its own.
NORESULT
Determines if the "ok" text is output in headless mode after successfully executing a line.
NOCOOKING
Dunno.
NOUNDOS
The server does not create undos, and will not appear in the Command Histroy's unod list or history. This used for the special-case of the built-in command line interpreter, since commands implicitly have undos and are directly handled by the undo systme. It is extremely dangerous to perform undos (intentionally or not) with this flag set.

Get the prompt string. CURRENT returns the active prompt based on the state of the interpreter. ALTERNATE gives the other possible prompt, if any.

(122) SDK: ILxLineInterpreter interface
         LXxMETHOD(  LxResult,
 Prompt) (
         LXtObjectID              self,
         const char             **prompt,
         unsigned                 type);

(123) SDK: Declarations
 #define LXiLINT_CURRENT          0
 #define LXiLINT_ALTERNATE        1

Execute a line. The flags are used for executing commands, and the execution object receives the results. Errors can be returned as the return value or through the message object, although return values take precedence. The special value LINEISCOMMENT can also be returned.

(124) SDK: ILxLineInterpreter interface
         LXxMETHOD(  LxResult,
 Execute) (
         LXtObjectID              self,
         const char              *line,
         int                      execFlags,
         LXtObjectID              execution);

The execution object is just a way for the interpreter to pass results back to the caller.

(125) SDK: Declarations
 #define LXu_LINEEXECUTION       "16947735-3797-444C-A907-DADD8165F4FB"

All of these methods are optional and hold the results of ececuting the interpreted line.

CookedLine
the line string echoed back after processing. For the command interpreter this includes normalizing arguments.
Message
a Message object holding the result code and success/failure statement.
Results
a ValueArray object holding a list of query results.
ResultHints
hints for decoding integer results into strings.
Info
text lines to report status back to the user. This may be called multiple times.

(126) SDK: ILxLineExecution interface
         LXxMETHOD(  LxResult,
 CookedLine) (
         LXtObjectID              self,
         const char              *text);
 
         LXxMETHOD(  LxResult,
 Message) (
         LXtObjectID              self,
         LXtObjectID              message);
 
         LXxMETHOD(  LxResult,
 Results) (
         LXtObjectID              self,
         LXtObjectID              valArray);
 
         LXxMETHOD(  LxResult,
 ResultHints) (
         LXtObjectID              self,
         const LXtTextValueHint  *hints);
 
         LXxMETHOD(  LxResult,
 Info) (
         LXtObjectID              self,
         const char              *text);

(127) User Class: LineInterpreter method

(128) User Class: LineExecution method

Empty LineInterpreter Python user class.

(129) PY: LineInterpreter method
 pass

Empty LineExecution Python user class.

(130) PY: LineExecution method
 pass

ILxScriptLineEventID Interface

This interface provides the line number edited and the script it was edited in.

(131) SDK: Declarations
 #define LXu_SCRIPTLINEEVENT     "DABF6619-A4B5-4919-8389-8C54B39422E4"
 #define LXa_SCRIPTLINEEVENT     "scriptlineevent"

(132) SDK: ILxScriptLineEvent interface
         LXxMETHOD(  LxResult,
 Index) (
         LXtObjectID              self,
         unsigned int            *index);
 
         LXxMETHOD(  LxResult,
 Script) (
         LXtObjectID              self,
         void                   **ppvObj);

That's all there is to it.

Empty ScriptLineEvent Python user class.

(133) PY: ScriptLineEvent method
 pass

Macros

Macros are a basic form of internal script. They are a simple list of commands that are executed in order with no flow control. They support arguments in the form of %1, %%2, etc., much like MS-DOS scripts.