Dialog Commands

From The Foundry MODO SDK wiki
Jump to: navigation, search

Scripts and plug-ins can present various dialogs to request user input, including information, warning, confirmation, yes/no/all/ cancel, file open, file save and directory dialogs. These are all handled through the dialog series of commands.

Overview

The dialog commands are executed in the following order to create, present and obtain the result of a dialog.

  • dialog.setup defines the kind of dialog you want to create
  • Other dialog commands are executed to set the title, file format, help URL, etc.
  • dialog.open opens the dialog and presents it to the user. The command blocks until the user dismisses the dialog.
  • dialog.result returns the user's choice.

Dialogs Setup

The first step to creating any dialog is to call dialog.setup. This determines the dialog type.

dialog.setup style:{info|warning|error|okCancel|yesNo|
                    yesNoCancel|yesNoAll|yesNoToAll|saveOK|
                    fileOpen|fileOpenMulti|fileSave|dir}
  • info, warning and error styles display notification dialogs with a single OK button.
  • okCancel and yesNo style dialogs have two buttons, and are used for simple confirmations.
  • yesNoCancel, yesNoAll, and yesNoToAll dialogs provide confirm/abort capability for loops.
  • saveOK dialogs are used to confirm that a save should be performed, such as when saving over a file or quitting without saving.
  • fileOpen dialogs are used to choose a single file from a system file dialog .
  • fileOpenMulti dialogs are used to choose one or more files from a system file dialog.
  • fileSave dialogs are used to choose a location to save a file from a system file dialog .
  • dir dialogs are used to choose a directory from a system directory dialog .

Only one dialog can be created at a time. Calling dialog.setup resets any previously defined dialog.

Creating a Yes/No Dialog: dialog.setup

A yesNo dialog has two buttons labeled Yes and No. To create a one, we might use this command:

dialog.setup yesNo

Title

The dialog.title command lets you set the string that appears in the dialog's title bar.

dialog.title "Confirm Operation"

The title can be a simple static string, or it can be obtained from a message table stored in a config. Message table lookups use the format @table@msg@ for a dictionary lookup, or @table@@id@ for an integer ID lookup. Using message tables allows the interface to be translated for different languages without editing the script or plug-in itself.

Body Text

To set the body of the dialog, we use dialog.msg. Again, the message can be either a static string or a message table lookup as described above.

dialog.msg "Perform the operation?"

Message Tables and Substitutions

Message table strings may have arguments in the form of %1, %2, etc. These can be set with dialog.msgArg, which takes the argument number, the datatype and the value to set it to.

dialog.msg "@table@msg@"
dialog.msgArg 1 string "test"

Help URLs

A help URL can also be included in the dialog through dialog.helpURL. This normal points to a help file on the local system, but can be any valid URL. When set, a ? button will appear in the dialog, and clicking it will go to that URL.

dialog.helpURL "http://www.google.com"

Default Result

As with any dialog, these dialogs can be suppressed by the caller of your script or plug-in. A default result can be set for the dialog in case that happens. For files and directories, this will also be displayed as the path when dialog is displayed. The 'dialog.result command is used to both set the default value and to read out a new value. This does not need to be called for information dialogs, as they have only one button and thus always return ok.

Text hints can be used when setting or reading dialog.result's value. This can be one of cancel, no, ok, yesToAll, or noToAll. The hint yes can be used as a synonym for ok when setting the default value, but ok will always be returned as both resolve to the same integer. Be careful when working with yesNo and okCancel dialogs, as while yes and ok are both the same value, no and cancel are not.

dialog.result ok

Dialog Result Codes Table

Here's a table of the possible dialog result codes from the informational dialogs.

Type Name/Buttons Result Code for Button
cancel no ok yesToAll noToAll
info Info (OK only) (none) (none) OK (none) (none)
warning Warning (OK only) (none) (none) OK (none) (none)
error Error (OK only) (none) (none) OK (none) (none)
okCancel OK/Cancel Cancel (none) OK (none) (none)
yesCancel Yes/No (none) No Yes (none) (none)
saveOK Save/Don't Save/Cancel Cancel Don't Save Save (none) (none)
yesCancel Yes/No Cancel No Yes (none) (none)
yesNoAll Yes/No/Yes To All/No To All (none) No Yes Yes To All No To All
yesNoToAll Yes/No/Yes To All/No To All Cancel No Yes (none) No To All

Displaying the Dialog

Now that all the dialog information is set, it can be presented with a call to dialog.open.

dialog.open

dialog.open will block until the user has made a choice.

Note that the dailog.open command fails with an abort code if the user hits a no or cancel style button. In Perl and Lua you can simply ignore the error code, but in Python this will throw an exception, which you will need to catch and optionally ignore, This behavior allows the command to be more generally tested for success or failure without using dialog.result.

Results

Once the dialog has been dismissed, dialog.result can be queried to see which button was pressed. For a file dialog, the return value will be one or more paths to the selected file(s), while for the other dialogs it will be one of the result codes from the table above.

dialog.result ?

Examples

Yes/No Dialog Perl Script Example

This simple Perl script demonstrates opening a yesNo dialog and testing which button was pressed.

  1. #! perl
  2.  
  3. # Setup the dialog
  4. lx( "dialog.setup yesNo" );
  5. lx( "dialog.title "Confirm Operation"" );
  6. lx( "dialog.msg "Perform the operation?"" );
  7. lx( "dialog.result ok" );
  8.  
  9. # Open the dialog and see what button was pressed 10) 
  10. lx( "dialog.open" );
  11. my $result = lxq( "dialog.result ?" );
  12. if( $result eq "no" ) {
  13.      # User hit cancel
  14. }

Yes/No Dialog Python Script Example

This is simple Python example opens a similar yesNo dialog. It uses an exception handler to handle the "no" case that is thrown when the user cancels the dialog. If no exception was thrown, we can assume the user clicked "Yes".

  1. #python
  2. # Written by Stuart Hall
  3.  
  4. import lx
  5.  
  6. try:
  7.     # set up the dialog
  8.     lx.eval('dialog.setup yesNo')
  9.     lx.eval('dialog.title {Confirm Operation}')
  10.     lx.eval('dialog.msg {Perform the operation?}')
  11.     lx.eval('dialog.result ok')
  12.  
  13.     # Open the dialog and see which button was pressed
  14.     lx.eval('dialog.open')
  15.     lx.eval("dialog.result ?")
  16.     lx.out("Yes")
  17.  
  18. except:
  19.     lx.out("No")

Yes/No/Cancel Dialog Python Script Example

This simple Python example opens a yesNoCancel dialog and retrieves the result. It uses an exception handler to handle the "no" and "cancel" cases that are thrown when the user cancels or presses no, and queries for the result directly to differentiate between no and cancel.

  1. #python
  2. # Written by Chris Hague
  3.  
  4. import lx
  5.  
  6. # set up the dialog
  7. lx.eval('dialog.setup yesNoCancel')
  8. lx.eval('dialog.title {Really?}')
  9. lx.eval('dialog.msg {Are You Sure?}')
  10.  
  11. # Open the dialog and see which button was pressed
  12. try:
  13.     lx.eval('dialog.open')
  14.     userResponse = lx.eval("dialog.result ?")
  15.  
  16. except:
  17.     userResponse = lx.eval("dialog.result ?")
  18. lx.out("Thank you for pressing %s." % userResponse)

File Dialogs

Creating a file or directory dialog is very similar to creating an information dialog. The fileOpen type opens a dialog asking for a single file, while fileOpenMulti allows for multiple selection within the file dialog. The fileSave type is similar to fileOpen, but warns if the selected file already exists. The dir type opens a dialog for selecting a directory.

In all cases, the dialog.result command can be used to set the initial path for the dialog. After the dialog is dismissed, dialog.result can be queried for the chosen path. In the case of fileOpenMulti, this will return an array of paths.

Open File Dialogs

The basic setup for a file dialog is just like that of an information dialog.

dialog.setup fileOpen
dialog.title "Select a file to open"

Setting the Filetype

Open dialogs support filtering the load dialog by file type. A file type is the class of data to be loaded or saved, such as an image or a scene. Save dialogs use the file type to provide a list of accepted file formats, plus the default file format displayed in the dialog. A file format is a specific format within that file type, such as a Targa or JPEG image, or an LXO or LWO object.

The file type is set with dialog.fileType, where the argument is one of the known file types, such as text, script, config, macro, image, and so on. Alternatively, the name of any specific loader plug-in can also be used, such as $LWO. A list of loaders can be obtained with the hostservice ScriptQuery interface. Furthermore, there is a special $temp file type, which can be filled in with dialog.fileTypeCustom. If no filetype is set, all files will be shown.

dialog.fileType text

The file type of a specific loader can be found by querying its loader.classList tag from the hostservice ScriptQuery interface. You must first "select" the loader before you can query it with server.infoTag. This example queries the LWO2 loader for its class.

query hostservice server.name ? loader/$LWO2
query hostservice server.infoTag ? loader.classList

Note that this returns a space-delimited list of classes. Only one class should be passed to dialog.fileType, so you'll need to extract the first one. In Perl, this can be done using split().

  1. # "Select" the loader we want to query the tags of
  2. lxq( "query hostservice server.name ? loader/$LWO2" );
  3.  
  4. # Query the loader.classList tag
  5. my $classList = lxq( "query hostservice server.infoTag ? loader.classList" );
  6.  
  7. # Split the list at spaces
  8. my @classes = split(' ', $classList);
  9.  
  10. # Setup the dialog with the first file type in the list 11) lx( "dialog.setup fileOpen" );
  11. lx( "dialog.fileType @classes[0]" );
  12. lx( "dialog.open" );

Default Paths

When the user chooses a file, the new location is stored in the config so that the next time the dialog is opened the file requester will point to that location. By default, all file dialogs point to the same place for a given file type, but it is often useful to be able to start at different locations depending on how the file will be used. For example, you generally don't store your texture images with your final render images.

You can tell modo to separately remember a separate default file dialog path for your script for a particular file type by appending an @ and a name to the end of the file type passed to dialog.fileType. The tag can be any internal (ie: alphabetical characters only) string you like, and you may reuse tags defined by other systems. For example, the image file type could default to directories that the user previously navigated to for clips (textures) or renders by specifying item@clip or item@render as the file type.

The following example uses the text file type, storing and pulling the default path from the ForMyScript tag in the configs.

dialog.fileType text@ForMyScript

Default Filename

The path the user has chosen is returned by dialog.result, but this can also be used to set a default open or save path (full path with filename), or just a default filename relative to the current path.

dialog.result "MyFile.txt"
dialog.result "c:MyPathMyFile.txt"
dialog.result "c:MyPath"

If you pass in just the filename, as in the first example, then the file requester will start in the directory last used for that file type, as described above. If a fully qualified path is used, then any previously stored paths are ignored. This can become important when want to create an "export" or "save as" dialog where the user may commonly want to write to an alternate directory than the one the file originally existed in.

Displaying a File Dialog and Obtaining the Result

File dialogs are opened in the same manner as other dialogs, through the dialog.open command. The chosen path is read out by querying dialog.result. The latter will fail if the user canceled the dialog. For more information on handling command execution failures, see the specific scripting systems for how to handle command failure.

dialog.open
dialog.result ?

Multi-Select File Dialog Perl Script Example

This Perl script demonstrates the use of a multi-select file dialog.

  1. #! perl
  2.  
  3. # Setup the dialog
  4. lx( "dialog.setup fileOpenMulti" );
  5. lx( "dialog.title "Select Text Files"" );
  6. lx( "dialog.fileType text@ForMyScript" );
  7. lx( "dialog.result "c:\InitialPath"" );
  8.  
  9. # Open the dialog and get the list of files the user selected
  10.  if( !lx( "dialog.open" ) ) {
  11.       # User canceled the dialog
  12.  }
  13.  
  14.  my @files = lxq( "dialog.result ?" );
  15.  foreach my $f (@files) {
  16.       # Process each filename
  17.  }

Save Dialog

A save dialog is identical to an open dialog, but adds dialog.fileSaveFormat to select a specific default file format within the file type set by dialog.fileType. This format will be selected by default when the dialog opens, and the one chosen by the user can be read by querying dialog.fileSaveFormat.

The file format can be set either by its default extension, which is the default behavior, or by the file format's internal name. The list of available formats can be found using the hostservice ScriptQuery interface. Which method is used is determined by the command's second argument. Either way, both the extension and format can be read out by querying dialog.fileSaveFormat.

In this example, a save dialog is set up to use the image file type, and a default path is chosen.

dialog.setup fileSave
dailog.result "c:InitialPath"
dialog.fileType image@ForMyScript

A list of file types for a particular format can be obtained by querying the hostservice server.infoTag attribute with the saver.outClass selector, similar to how loader file types are queried.

query hostservice server.name ? saver/$Targa
query hostservice server.infoTag ? saver.outClass

The Targa image file format is then chosen as the default save format. This can be done either by file extension:

dialog.fileSaveFormat tga extension

Or it can be done by the format's name:

dialog.fileSaveFormat $Targa format

Next the file dialog is opened. This will fail if the user hit canceled, at which point a script could abort the operation.

dialog.open

Finally, the path the user entered and the format and extension the user chose are ead.

dialog.result ?
dialog.fileSaveFormat ? format
dialog.fileSaveFormat ? extension

Custom File Types

It is also possible to define a custom file type through $temp, which can represent any file formats you like through the dialog.fileTypeCustom command. Initially, this file type contains no formats, and is reset by dialog.setup. You can call dialog.fileTypeCustom multiple times to add any number of formats to the type. The first format added is automatically selected as the default file format.

dialog.fileTypeCustom takes four arguments. The first is a name for the format, such as targa or lwo. This is an arbitrary internal name for use by the script, and can be read out after the dialog is dismissed by querying dialog.fileSaveFormat. The second argument is the username for the format, which will be displayed in the dialog and may contain spaces, mixed case, and so on.

The final two arguments are the load pattern and the save extension. The pattern is a semicolon-delimited list of file extensions that the particular file format supports. These are used to filter the load dialog. Each extension must include a leading asterisk and period for the filtering to work properly, such as *.jpg;*.jpeg.

The save extension is a single extension that will automatically be appended to the end of the filename selected in a save dialog. The period should not be entered, just the extension like lwo, tga or txt. You only need to specify the load pattern or save format as appropriate to the kind of dialog you're opening.

Here is a simple Perl script example that lets the user decide if it should save some information as an XML file or an ASCII text file. The script adds two file formats, xml and text, as a custom file type, and after the dialog closes it retrieves the file name, format and extension of the format the user chose.

  1. #! perl
  2.  
  3. # Setup the save dialog
  4. lx( "dialog.setup fileSave" );
  5. lx( "dialog.title "Save Data"" );
  6. lx( "dialog.result "c:\InitialPath"" );
  7.  
  8. # Add two file formats, xml and text
  9. lx( "dialog.fileTypeCustom xml "XML" "*.xml" xml" );
  10. lx( "dialog.fileTypeCustom text "ASCII Text" "*.txt;*.text" txt" );
  11.  
  12. # Open the dialog
  13. if( !lx( "dialog.open" ) ) {
  14.     # User canceled the dialog; abort
  15. }
  16.  
  17. # Get the filename from the dialog
  18. my $filename = lxq( "dialog.result ?" );
  19.  
  20. # Get the file format, which will be xml or text
  21. # (the first argument passed to dialog.fileTypeCustom)
  22. my $format = lxq( "dialog.fileSaveFormat ? format" );
  23.  
  24. # Get the format's extension, which will be xml or txt
  25. # (the last argument passed to dialog.fileTypeCustom)
  26. my $ext = lxq( "dialog.fileSaveFormat ? extension" );

Custom File Type Dialog wrapper function in Python

A convenient Python wrapper function that can be used for both saving and loading custom file types:

def customfile(type, title, format, uname, ext, save_ext=None, path=None):
    ''' Custom file dialog wrapper function
 
        type  :   Type of dialog, string value, options are 'fileOpen' or 'fileSave'
        title :   Dialog title, string value.
        format:   file format, tuple of string values
        uname :   internal name
        ext   :   tuple of file extension filter strings
        save_ext: output file extension for fileSave dialog
        path  :   optional default loacation to open dialog
 
    '''
    lx.eval("dialog.setup %s" % type)
    lx.eval("dialog.title {%s}" % (title))
    lx.eval("dialog.fileTypeCustom {%s} {%s} {%s} {%s}" % (format, uname, ext, save_ext))
    if type == 'fileSave' and save_ext != None:
        lx.eval("dialog.fileSaveFormat %s extension" % save_ext)
    if path != None:
        lx.eval('dialog.result {%s}' % path)
    try:
        lx.eval("dialog.open")
        return lx.eval("dialog.result ?")
    except:
        return None


Example usage:

swfile = customfile('fileOpen', 'Open Solidworks file', ('SWO',), 'Solidworks file', ('*.SLDASM;*.SLDPRT',),'SLDASM')

More Information