ScriptQuery Overview

From The Foundry MODO SDK wiki
Revision as of 11:53, 3 March 2014 by Jangell (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Note: While the ScriptQuery interfaces will continue to function, they will likely not be expanded much in the future, as they are generally deprecated in favor of the much more powerful Python API introduced in 701.

Overview

Command queries provide a fair bit of information about the system state, but they can't practically provide information about the individual polygons in a mesh or the weights in a vertex map. For this lower level information, modo provides a series of ScriptQuery interfaces.

ScriptQuery interfaces accessed as a command system feature or through the COM/C++ interfaces, and are independent of any scripting language or plug-in. You can try them out using the Command Entry and Results tab of the Command History Viewport. These same principles apply when using a ScriptQuery from within a script.

While the ScriptQuery interfaces are most often used by scripts, they can also be used by plug-ins. However, plug-ins more often use lower-level calls through the SDK. All service-class plug-ins must have start with a ScriptQuery() method, thus allowing any service to provide scripting support. All the method is always present, it is not implemented by all services.

When using Python, you can use either the query command described below, or you can use a more SDK-like ScriptQuery class. When using Perl or Lua, you'd use the query command just like you would in the Command Entry in the Command History. See the |Python article for more information.

This article mainly focuses on accessing the ScriptQuery interfaces through the query command.

The query Command

The query command provides generic access to these interfaces from any scripting language. Plug-ins can also use this command, but usually they will either directly instance the ScriptQuery object from the service interface, or use other SDK methods and interface to get the information in another manner. The query command is defined like so:

query service:string
      attribute:string
      #value:*
      <select:string>

The service argument is the name of the service you wish to query. Examples are Layersservice and Commandservice. A full list of script services is available in the ScriptQuery category.

Attributes and Selectors

The ScriptQuery interfaces operate on two main components: attributes, which are the properties being queried, and selectors, which determines what is being queried. When using the query command, these are set as arguments on the command. When using the SDK's COM/C++ interface, these are methods on the object. They are used in a very similar manner: in the command you set the argument, while in the SDK you call the method.

Attributes

The attribute argument determines the specific information to be obtained from the service. Some attributes require a selection, while others do not. An empty attribute string in the form of "", {} or [] provides a list of all possible attributes supported by the service For example, executing this query from the Command History viewport will list all of the available commandservice attributes:

query commandservice "" ?

Attribute names are similar to command names, and consist of two parts: the type of selection affected, and the specific property of that selection. command.username gets the username of a command; layer.name in layer service operates on a layer selection, and so on.

Selectors

The select argument is only necessary for attributes that require some sort of context. This should not be confused with selection system, which is used by the user to change the state of the application, such as executing select.layer to change the currently active layer. Instead, this selector is used to let the ScriptQuery interface know which element the attribute is to obtain information about. In this example, the command.username attribute needs to know which command to get the username of, so we "select" a command for the query:

query commandservice command.username ? pref.value

In some cases it is necessary to query one attribute before you can query another. For example, before using any of layerserivice's vert.??? attributes, you must first "select" a layer by querying one of the layer.??? attributes. This ensures that the layer has been "selected" so that the the vert.??? attributes have something to operate one.

If a selector has already been specified once, you do not need to specify it again before making another query on the same selector. When using the SDK the Python ScriptQuery class, this means that after you choose an element with the Select() method, you can repeatedly call the Query() method to get the value of different attributes element without having to keep Select() method again. The query command emulates this behavior when you omit the select argument.

This example gets the username of pref.value, and then gets its tooltip. Since pref.value was previously set as the selector, there is no need to specify it again until you want to query a different command.

query commandservice command.username ? pref.value
query commandservice command.tooltip ?

Some attributes require selections, but others do not. For example, the "commands" attribute returns a full list of all commands, and ignores any selection. If a selection is required but none was provided, or the previous selection doesn't match the attribute, or the attribute couldn't deal with the new selection for some reason, an error is reported.

More on Selectors

Selectors can be a bit confusing, so we'll clarify them a bit further. Lets say you just started modo up, which means that all selectors are unset. The following command performs a query, but since the fourth argument is not set, it does not change the current selector. Since the commands attribute does not require a selector, this works fine, returning a complete list of commands.

query commandservice commands ?

Next we want to get the username of a command. The command.username attribute requires a command name as a selector so it knows what to operate on. Simply entering the following will result in an error because you did not specify a selector.

query commandservice command.username ?

To tell it which command we want to get the username of, we need pass a command name (say, from the previous commands query) as the selector argument.

query commandservice command.username ? tool.set

This now returns the username of the tool.set command, which is what we wanted. If we want another attribute, such command.help, you can do so in the same manner.

query commandservice command.help ? tool.set

However, since you previously selected tool.set in the command.username query, you can omit the selector this time.

query commandservice command.help ?

Thus, you only need to specify the selector if you want to change it to something else. To summarize, the query command does two things:

  • Specifies an attribute and returns the queried value (the Query() method in the SDK and the Python class)
  • Optionally changes the selector that the attribute operates on (the Select() method in the SDK and the Python class)

Using Multiple Selectors

Some attributes require multiple selectors. For example, to query a specific server's tags from the host service ScriptQuery interface, you must specify both a server selector a tag selector. However, you can only pass a single selector to the query command (or the Select() method) a time.

You can effectively pass multiple selectors by querying a higher-level attribute first, then querying the lower-level attribute you are interested in. For example, we can use the server.name attribute of the host service ScriptQuery interface to "select" the loader/$LXOB server.

query hostservice server.name ? loader/$LXOB

We don't actually care about the results of the query; we just wanted to select loader/$LXOB. We can ask for hostservice for a tag with the server.infoTag attribute and the name of the tag we're interested in as the selector.

query hostservice server.infoTag ? loader.classList

We now have a list of file types that we can split apart and pass to the dialog.fileType command.

Queried Values

The query command's read-only value argument returns the value of a specific attribute information, and should always be set as a question mark to query the value. In the SDK and the Python class, values are returned via the Query() method, which is also how the attribute is passed in. A query can return a single value or multiple values depending on the service, attribute or selector. The return type is a Value Array through the SDK, and a native array for the scripting languages.

More Information