USER DIALOGS

A new year. A new InDesign CC version (2017); and lots to talk about.

Whether you are new to working with scripts or an old hat, one thing that is for certain, almost every script you write will in some way need to communicate with the user.

The dialogs built into JavaScript and AppleScript have a limited user interface, and in the event you want more than one value returned, the Prompt dialog for JavaScript (Display Dialog for AppleScript) just doesn’t cut it. For this, there are a number of other options depending on the language you are using. Adobe provides a custom dialog which is fairly easy to use, With adequate dialog controls (widgets) within an intuitive user interface. The only problem is that these dialogs are modal.

MODAL DIALOGS

Modal dialogs take over the system until the dialog is closed. No other user activity can be performed by the target application until the dialog is closed.

For most processes, the modal dialog is amply adequate. The user enters information or makes choices, and clicks a button to dismiss the dialog. From there the script takes over to accomplish its task. If there is no reason that the dialog must remain open while other processes take place, you should find its ease of use may make it your preferred user interface. Dialog controls that the custom dialog provides include:

  • editbox (input that can be configured for text, integer, real, percent, angle, or measurement values)
  • combobox (input editbox with a list dropdown with variations to accommodate integer, real, angle, measurement, and percent values)
  • dropdown (list of values)
  • checkbox
  • radio button
  • enabling group (dialog control that when checked enables controls within its group)
  • panel (a bordered container used to visually group controls with similar functionality)

CUSTOM DIALOG

For a dialog that offers a number of user dialog controls in a fairly intuitive interface, the custom dialog provided by an Adobe application may be your most used./p>

It is easy to understand and set up. Its downside is that it is modal. This means that the dialog must be dismissed before any other activity can be done by the user within the application. For most purposes, this is not a problem.

Interface Dialog as a Function (Handler)

The code structure for creating and utilizing a dialog is fairly consistent:

  • Pass dialog name and properties to dialog function (handler)
  • Establish the user interaction level (script preferences)
  • Create the dialog
  • Add statements to create dialog controls that assign variables to hold values provided by the user
  • Show the dialog and return the result of the user clicking either the OK, or Cancel button.
  • If user clicks OK, get values from dialog controls
  • Destroy the dialog
  • Throw an error if user clicked Cancel
  • Return value or values from dialog result

Let’s see how this works in code with a simple dialog that gets the user’s response from a radio button group.

The following dialog will return a value of 0, 1, or 2 depending on the radio button chosen when the OK button is clicked.

ExtendScript

//call function within a try/catch block to handle error if thrown
try {
  var userResponse = dialogWRadio ("PDF Preferences", true, "PDF Prefs");
  //alert ("user entered" + userResponse);
} catch (e) {
  alert (e);
}
function dialogWRadio (dlgName, cancelIt, dlgLabel) {
  var userCancelled = true; //is set to false if user clicks OK button 
  var oldPrefs = app.scriptPreferences.userInteractionLevel;
  app.scriptPreferences.userInteractionLevel=UserInteractionLevels.INTERACT_WITH_ALL;
  //create dialog
  var dlgRef = app.dialogs.add({name:dlgName, canCancel:cancelIt, label:dlgLabel});
  //add a column
  var dlgColumn = dlgRef.dialogColumns.add();
     //add a row
     var dlgRow = dlgColumn.dialogRows.add();
     //add radio elements to row
     var rGroup = dlgRow.radiobuttonGroups.add();
     rGroup.radiobuttonControls.add({staticLabel:"Hi-res_PDF", checkedState:true});
     rGroup.radiobuttonControls.add({staticLabel:"Low-res_PDF"});
     rGroup.radiobuttonControls.add({staticLabel:"PRINTER"});
    if (dlgRef.show() == true) {
        userCancelled = false;
           var radioValue = rGroup.selectedButton;
    }
dlgRef.destroy();
app.scriptPreferences.userInteractionLevel=oldPrefs;
if (userCancelled) {
    throw ("User Cancelled");
 }
return radioValue;
}  

AppleScript

(*Result from dialog will return 0, 1, or 2 to correspond with Hi-res, Low-res, or PRINTER choices*)
try
   set userResponse to dialogWRadio("PDF Preferences", true, "PDF Prefs")
   activate
   display alert ("user entered " & userResponse)
on error (errMsg)
   activate
   display alert (errMsg)
end try
--userResponse
on dialogWRadio(dlgName, cancelIt, dlgLabel)
   tell application "Adobe InDesign CC 2017"
	activate
	set userCancelled to true
	set oldPrefs to user interaction level of script preferences
	set user interaction level of script preferences to interact with all
	set dlgRef to make dialog with properties {name:dlgName, can cancel:cancelIt, label:dlgLabel}
	tell dlgRef
	   set dlgColumn to (make dialog column)
	   tell dlgColumn
		set labelRow to make dialog row
		tell labelRow to make static text with properties {static label:"PDF Output"}
		set dlgRow to make dialog row
		tell dlgRow
		   set rGroup to make radiobutton group
		   tell rGroup
			make radiobutton control with properties {static label:"Hi-res_PDF", checked state:true}
			make radiobutton control with properties {static label:"Low-res_PDF"}
			make radiobutton control with properties {static label:"PRINTER"}
		   end tell
		end tell
	   end tell
	end tell
	set userOK to show dlgRef
	if (userOK) then
	   set dlgResult to selected button of rGroup
	end if
	destroy dlgRef
	set user interaction level of script preferences to oldPrefs
	if (userOK is false) then
	   error ("User Cancelled")
	end if
   end tell
   return dlgResult
end dialogWRadio

There are a number of ways the example scripts can be coded. For Javascript, an optional way is to use the with operator option. Instead of assigning a variable to a parent object (such as the dialog itself), an arbitrary variable is created in memory which references the object. You will find examples of this structure in the Sample scripts provided by Adobe. For instance, the AddGuides.jsx script uses the with operator. The script starts by creating a variable for the dialog and from there uses with to reference each parent object. Of course, for those objects that will have input values that will need to be referenced later, variables are assigned.})

...
var myDialog = app.dialogs.add({name:"AddGuides"});
with(myDialog) {
  with(borderPanels.add()){
    staticTexts.add({staticLabel:"Add Guides At:"});
    with(dialogColumns.add()) {
      var myTopCheckbox = checkboxControls.add({staticLabel:"&Top", checkedState:true});
      var myLeftCheckbox = checkboxControls.add({staticLabel:"&Left", checkedState:true});
      ,,,
    }
  }
}
myReturn = myDialog.show();
...

SCRIPT LIBRARY

The whole idea of writing and using scripts is to eliminate repetitive processes while ensuring consistency. If you haven’t created a library of script functions (handlers) of your own, may I suggest that you start today. Copy the code from above to provide a template with which you can create your next user interface dialog. In the next few blog installations, we will be creating some simple projects that will do just that.

OTHER USER INTERFACE OPTIONS

ScriptUI

For the JavaScript language, Adobe provides an alternate dialog module. If you open the Add Guides Sample script provided by Adobe, in later versions of InDesign, you will see that it also includes a ScriptUI version of the dialog. ScriptUI seems to present some problems for beginning users. One problem I have is that the author of the script has forgotten to dismiss the window, and ends up with a number of windows in memory even before the script finishes testing. If you are interested in learning more about ScriptUI may I suggest that you look up the documentation provided on the web by Peter Kahrel (www.kahrel.plus.com/idesign/scriptui.html).

AppleScript Objective-C

Introduced for Macintosh in OS X10.6, AppleScript Objective C provides a way to create rich user interfaces. It was designed to allow developers to write AppleScript-based applications with a rich interface in Xcode. For those wanting to take advantage of tis powerful language, Shane Stanley has written several manuals for writing AppleScriptObjC. His latest, Everyday AppleScriptObjC, Third Edition, is highly recommended. For more see macosxautomation.com/applescript/apps/everyday_book.html.