Javascript Commands For After Effects Program (scriptui)


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
no-echo text eld
See
numeric input
See also
onChanging
onDoubleClick
onResize
Mac
onResizing
onShow
group
window
Index
Note
: Blue page numbers refer to text in
a sidenote
ActionScript
and Flash
AfterEects
.addEventListener()
Aigon, Loïc
alert()
native
scripted, scrollable
in edittext controls
in a group
in a window
anonymous function
application icons
ExtendScript Toolkit
le formats
InDesign
Photoshop
In CC2015, the way that
– The display of
resizing windows
Changes in CC
ScriptUI has undergone several changes in the transition from CS6 to CC.
The most noticeable change is the appearance of the interface. The window
background is darker; buttons are less rounded; lists have row separators; nodes
in treeviews are now triangles – these are appearances only. Here is an example
that illustrates most of these changes: the darker background, dierent nodes,
InDesign up to CC
InDesign from CC
But there are also various changes in ScriptUI’s behaviour. I’ll list here the ones
Appendix 2: ESTK resource icons
The screenshot shows the ESTK
resource icons. They can be used only when
function
graphic_to_text
/*array of file objects*/
var
outfile, s,

re1 = /^\(new String\(/,

re2 = /\)\)$/;
for
var
infiles.length
i].exists


File
i].fullName.replace
/\.(png|idrc)$
'.txt'

outfile.open
'w'

i].encoding
'BINARY'

i].open('r');  
i].read

outfile.write
'var '
outfile.name.replace
'.txt'

outfile.write
s.toSource
.replace
re1,
.replace
re2,

outfile.write

i].close();  
outfile.close

The function's input is an array of le objects. Here are some examples:
graphic_to_text
Folder
"/d/test/"
To embed a graphic in a script le we must convert the contents of the binary
le to a string. The following script does that:
var
File
"/d/test_jpg/icon.png"
var
File
"/d/test_jpg/icon.txt"
infile.open
infile.encoding
"binary"
var
temp
infile.read
infile.close
outfile.open
"w"
outfile.write
temp.toSource
outfile.close
This results in a text le with a single, usually very long, line, which has the
following form:
(new String(". . ."))
To use the string in a script, open the le in a plain text editor and strip
String(
from the beginning and
from the end. Copy the string (including the
quote marks) and paste it into the script, declaring it as a variable. This variable
is used in the script instead of a reference to a le object. Our earlier code would
then look as follows:
var
myIcon
/* very long string */
var
new
Window
"dialog"
w.add
"iconbutton"
, undefined, myIcon
w.show
That's basically all there's to it. But the conversion script, above, is a bit unwieldy,
and I started using the following script, which is exible in its input and strips
the unwanted overhead away from the converted string.
fonts
http://www.indiscripts.com/post/2012/05/scriptui-fonts-facts
colour
https://forums.adobe.com/thread/2159810
Miscellaneous
http://forums.adobe.com/thread/1260079?tstart=0
Interactive dialog builders
Two dialog builders mentioned earlier –
Rapid ScriptUI and
ScriptUI Builder –
are no longer available. Slava
Boyko’s excellent DialogBuilder is available at
https://github.com/SlavaBuck/DialogBuilder
(it was last updated in August
2014).
A slightly dierent approach is David Van Brink’s
dialog builder.
This is not an interactive dialog builder like the three apps
mentioned
above, but rather a kind of interface for ScriptUI. See
http://omino.com/
pixelblog/2008/09/21/35/
Acknowledgements
I would like to thank Mark Francis of Adobe for sharing his knowledge of
ScriptUI and also the following people, most of whom are (or have been)
w.add
"iconbutton"
, undefined,
File
"/d/test/icon.png"
In itself this is convenient, but you should really check if the icon le is present
and provide some alternative just in case the le can't be found. So it would be
convenient if we could embed those icons in the script – and we can.
Using the ESTK's object-model viewer you can browse the ScriptUI object
model. And
Jongware's fabulous CS object browsers include a version for
ScriptUI (see http://www.jongware.com/idjshelp.html).
Another source of information is the collection of sample scripts that comes
with the ESTK, and which are listed on the rst page of the ScriptUI chapter
in the Tools Guide. To nd these scripts, search your hard disk for a le with
the name one of them (e.g. ColorPicker.jsx): their location depends on your
operating system and CS version.
A more interesting collection of scripts are those that can be found in the ESTK’s
Required
subdirectory. The scripts there form the basis of the ESTK’s interface
and use ScriptUI for their dialogs and other windows. This is a fascinating
collection, with many instructive techniques. Do
on any account change
these scripts. The location of the scripts depends on your OS and CS/CC version.
To nd the folder, search your disk for a script called 35OMVui.jsx.
Bob
Stucky has collected a number of educational scripts here: http://www.
just one edittext control. A call to
prop()
prints all properties and their current
values. A call to
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined,
"Cats"
prop
prop
e.graphics
Resources
Virtually the only real comprehensive ScriptUI resource is the dedicated chapter
in the Tools Guide that comes with the ESTK; you can nd it in the ESTK’s Help
menu. This is a PDF le called
JavaScript Tools Guide CSx/CC.pdf
EditText
active: false
alignment: undened
characters: undened
children:
graphics: [object ScriptUIGraphics]
helpTip:
indent: undened
justify: left
location: undened
maximumSize: 3790,1150
minimumSize: 0,0
parent: [object Window]
preferredSize: 35,20
properties: undened
shortcutKey: undened
size: undened
text: Cats
textselection:
type: edittext
window: [object Window]
windowBounds: 0,0,100,30
ScriptUIGraphics
BrushType: [object Object]
PenType: [object Object]
backgroundColor: undened
currentPath: [object ScriptUIPath]
currentPoint: undened
disabledBackgroundColor: undened
disabledForegroundColor: undened
font: Tahoma:12.0
foregroundColor: undened
var
new
Window
"dialog"
var
w.add
'button {text: "Continue", alignment: "fill", properties: {name: "ok"}}'
w.show
var
new
Window
"dialog"
var
w.add
panel.preferredSize.width
panel.add
'button'
panel.add
'button'
w.show
In a mixed style, however, you can't use
, and you have to use the array
var
new
Window
"dialog"
// All three variants work:
var
w.add
preferredSize: [200, undefined]
var
w.add
preferredSize: [200, -1]
var
w.add
preferredSize: [200, ]
panel.add
'button'
panel.add
'button'
w.show
You have to remember the order in which the start, minimum, and
values are given (50, 0, and 100, respectively, in the example). An much clearer
alternative to this is the following, still code-based, version:
var
w.add
slider.minvalue
slider.maxvalue
slider.value
The mixed style, on the other hand, is more compact and just as easy to
var
w.add
"slider {value: 50, minvalue: 0, maxvalue: 100}"
As with all JavaScript objects, the order in which the properties are given is
immaterial.
w.add
'edittext {preferredSize.width: 150}'
// All these are wrong
w.add
'edittext {preferredSize[0]: 150}'
w.add
'edittext {preferredSize {width: 150}}'
By chance I found that -1 can be used as the default value for a control. In the
w.add
'edittext {preferredSize: [150, -1]}'
var
new
Window
"dialog"
var
w.add
"button"
, undefined,
"Continue"
"ok"
b.alignment
"fill"
w.show
In mixed style, the button could be dened as follows:
function
myInput
var
new
Window
'dialog'
'Form'

'group'

'statictext {text: "Name:"}'

'edittext {text: "John", characters: 20, active: true, properties: {name:
"person"}}'


"group"

'button {text: "OK"}'

'button {text: "Cancel"}'

win.show
function
myInput
var
new
Window
"dialog"
"Form"
var
"group"

inpGrp.add
"statictext {text: 'Name:'}"

var
myText
inpGrp.add
"edittext {text: 'John', characters: 20, active: true}"
"group {alignment: 'right'}"

win.btnGrp.add
"button {text: 'OK'}"

win.btnGrp.add
"button {text: 'Cancel'}"
win.show
var
w.add
, undefined, 50, 0, 100
Note that capitalisation is slightly dierent: use
Button
StaticText
button
statictext
– the names of controls and properties are case-sensitive
in dierent ways depending on the coding style.
Code-based object
function
myInput
var
new
Window
"dialog"
"Form"
"group"

win.inpGrp.add
"statictext"
, undefined,

win.inpGrp.txt
win.inpGrp.add
"edittext"
, undefined,
"John"

win.inpGrp.txt.characters

win.inpGrp.active
"group"

win.btnGrp.alignment
"right"

win.btnGrp.add
"button"
, undefined,
"OK"

win.btnGrp.add
"button"
, undefined,
"Cancel"
win.show
win.inpGrp.txt
win.inpGrp.add
"edittext"
, undefined,
"John"
"personname"
var
bloke
win.findElement
"personname"
An alternative to this style is to use with statements, as in the forrowing
example:
Resource string
The rst alternative is the so-called resource string, in which the whole window
is presented as a single string that denes the window's characteristics as an
object. The script below is the script in p. 8 recast using a resource string.
Proponents of this style make the point that using resource strings encourages
the coder to separate the window's design from its functional component.
This is clear in the example: the resource string states only how the window
function
myInput
var
winResource
"dialog {text: 'Form', \

myInput: Group {\

n: StaticText {text: 'Name:'},\

myText: EditText {text: 'John', characters: 20, active: true}\


myButtonGroup: Group {alignment: 'right',\

b1: Button {text: 'OK'},\

b2: Button {text: 'Cancel'}\

var
myWindow
new
Window
winResource
myWindow.show
w.onShow
function
w.minimumSize
w.size
// define the initial standard size as minimum size
for
var
w.children.length
w.children
i].minimumSize
w.children
i].size
new
Window
'dialog'
'Test'
, undefined,
resizeable
w.alignChildren
'fill'
'fill'
w.add
'button {text: "Button 1"}'
w.add
'button {text: "Button 2"}'
w.onResizing
w.onResize
function
w.orientation
w.size.width
w.size.height
'row'
'column'
w.layout.resize
w.onShow
function
w.layout.resize
w.show
All that's needed is to check the shape of the container and change its
orientation accordingly.
For a owchart and a draft outline of ScriptUI's
layout manager, see
Marc
The window has two main alements, the edittext control and the group with
var
new
Window
"dialog"
"Resize"
, undefined,
resizeable
w.orientation
"row"
var
w.add
'edittext'
e.alignment
"fill"
"fill"
e.minimumSize
300, 200];   var
w.add
'group {orientation: "column"}'
g.alignment
'right'
'top'
g.alignChildren
'fill'
g.add
'button {text: "This"}'
g.add
'button {text: "That"}'
g.add
'button {text: "And the other"}'
// onResize needed on Mac OS X
onResizing
onResize
function
.layout.
resize
w.onShow
function
w.minimumSize
w.size
w.show
Another important step is the calculation of the minimum size of the window.
We do this in the
onShow
callback.
onShow
var
new
Window
'dialog {orientation: "row", alignChildren: ["
", "top"]}'
w.add
'panel {preferredSize: [150, 200]}'
var
w.add
'group {orientation: "column"}'
alignChildren
"fill"
g.add
'button {text: "Auto"}'
g.add
'button {text: "Instant preview"}'
g.add
'button {text: "OK"}'
g.add
'button {text: "Cancel"}'
w.show
g.alignChildren
"    ", "fill"
Resizing windows
Moving a window is easy: just grab the window's title bar and drag it to
somewhere else on the screen. This is useful when the window covers what you
were looking at.
It can also be useful to make windows resizable, but that's a bit more
complicated. The script below shows a simple window which can be resized. It
draws a window with an edit eld and a group with three buttons in it. The user
can resize the window in the usual way by clicking on a corner or a side of the
window's frame and dragging it left, right, up, or down.
Without
g.alignChildren = 'fill'
With
g.alignChildren = 'fill'
var
new
Window
'dialog'
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
p1.text
'Margins: default\rSpacing: default'
w.show
var
new
Window
'dialog'
w.margins
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
p1.text
'Margins: 0\rSpacing: default'
w.show
var
new
Window
'dialog'
w.margins
w.spacing
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
w.add
'edittext {preferredSize: [200, 100], properties: {multiline: true}}'
p1.text
'Margins: 0\rSpacing: 0'
w.show
alignment
Alignment
var
new
Window
'dialog {preferredSize: [250, "
var
w.add
'button'
b.alignment
'left'
var
w.add
'button'
b.alignment
'center'
var
w.add
'button'
b.alignment
'right'
var
w.add
'button'
b.alignment
'fill'
w.show
Vertical alignments are
top
center
bottom
var
new
Window
'dialog {preferredSize: ["
", 150], orientation: "row"}'
var
w.add
'button'
b.alignment
"    ", 'top'
var
w.add
'button'
b.alignment
"    ", 'center'
var
w.add
'button'
b.alignment
"    ", 'bottom'
var
w.add
'button'
b.alignment
"    ", 'fill'
w.show
is placed in front of the rst control. When you use
you should therefore
do a platform check and on Windows, also do a version check. The following
script illustrates:
var
new
Window
'dialog'
w.orientation
$.os.indexOf
'Windows'
parseInt
app.version
// On Windows, before CC
w.add
'button'
w.add
'edittext {preferredSize: [200, 100]}'
// On Mac or on Windows from CC
w.add
'edittext {preferredSize: [200, 100]}'
w.add
'button'
w.show
Margins and
Margins
w.margins
0, 0, 0, 0];w.margins
// same effect as previous line
w.margins.left
The order of the four values in the
margins
array is [left, top, right, bottom].
Predictably, apart from
height
maximumSize
has a property
as well. In
my experience,
maximumSize.width
isn't needed as much as
maximumSize.
height
– I use it only for resizeable windows.
But if you use a dual-monitor system, you may be in for a surprise:
maximumSize.width
considers both screens as one. For example, I have
two 24-inch 1920 × 1200 screens next to each other. The window property
maximumSize.height
for
var
$.screens.length
$.writeln
"Screen "
$.writeln
"top: "
$.screens
i].top
$.writeln
"left: "
$.screens
i].left
$.writeln
"bottom: "
$.screens
i].bottom
$.writeln
"right: "
$.screens
i].right
So the maximum width of windows placed on the rst screen is about 1900.
Minimum size
Use
minimumSize
Screen 0
top: 0
left: 0
bottom: 1200
right: 1920
Screen 1
top: 0
left: 1920
bottom: 1200
right: 3840
new
Window
'dialog'
100, 200, 300, 400]);   $.writeln
'Bounds: '
w.bounds
$.writeln
'Frame bounds: '
w.frameBounds
w.show
The output shows that the left, right, and bottom frame are 3 units wide, and
that the top of the frame is 30 units.
Maximum size
Maximum size
is needed to prevent controls from disappearing o the screen.
This could happen, for example, with long lists. The following script displays
a list of 100 items in a
list box, but the screen is clearly not tall enough to
accommodate that list: it manages 61 items on my screen.
var
new
Window
'dialog'
var
w.add
'listbox'
for
var
list.add
'item {text: '
w.show
var
new
Window
'dialog'
$.writeln
w.maximumSize.height
On my PC this prints
var
new
Window
'dialog'
var
w.add
'listbox'
for
var
list.add
'item {text: '
list.maximumSize.height
w.maximumSize.height
w.show
Bounds: 100,200,300,400
Frame bounds: 97,170,303,403
var
new
Window
"dialog"
// either of the following three:
w.location
100, 200];   w.location
w.location
"x:100, y:200"
w.show
The
w.location.x =
w.location[0] =
formats are possible only in
onShow
var
new
Window
"dialog"
w.onShow
function
w.location.x
w.location.y
w.show
Bounds
var
new
Window
"dialog"
// either of the following three
w.bounds
100, 200, 300, 400];   w.bounds
left
100, top
200, right
300, bottom
w.bounds
"left: 100, top: 200, right: 300, bottom: 400"
w.show
As with all controls, using the array notation, bounds can be included in the
control’s denition:
var
new
Window
"dialog"
Title"
100, 200, 300, 400]);w.show
A window’s bounds exclude the frame, so when you place a window at the top
left of a screen you should allow for the frame. The window’s bounds including
var
new
Window
"dialog"
w.preferredSize
300, 400];   w.preferredSize
300, height
w.preferredSize
"width: 300, height: 400"
w.preferredSize.width
w.preferredSize.height
w.preferredSize
0] = 300;   w.preferredSize
1] = 400;   w.preferredSize
var
new
Window
"dialog"
w.onShow
function
w.size
300, height
w.show
All the notations available for
preferredSize
can be used for
size
, too:
w.size
300, 400];   w.size
300, height
w.size
"width: 300, height: 400"
w.size.width
w.size.height
w.size
0] = 300;   w.size
1] = 400;Location

switch
.state

case
case
app.selection
0].noBreak
.state
.refresh
break

case
app.selection
0].noBreak
.state
.refresh
break




w.cbox.addEventListener
'click'
, mouseEventHandler

var
txt
app.selection
0].textStyleRanges.everyItem
.underline.join

txt.indexOf
'true'
txt.indexOf
'false'

Three-state checkboxes: Sprites
ScriptUI's checkbox controls are two-state: on or o. But in many cases – in
InDesign anyway – a text selection, for example, can be in three states: on, o,
or mixed. ScriptUI doesn’t provide anything natively for three-state boxes, but
with some (considerable) eort those three-state checkboxes can be added to
a ScriptUI panel.
The idea behind this is to create a so-called
sprite, as was shown by Marc
The red frame represents the
ScriptUI image object. The
graphic is moved horizontally.
Because the image object is
a third of the graphic's width,
only one state is ever shown.
CC-style
CS6-style
var
new
Window
'dialog'
'New text anchor'
w.group
w.add
'group'
w.group.add
'statictext {text: "New name:"}'
w.input
w.group.add
'edittext {characters: 20, active: true}'
w.buttons
w.add
'group {alignment: "right"}'

w.ok
w.buttons.add
'button {text: "OK", enabled: false}'

w.buttons.add
'button {text: "Cancel"}'
w.input.onChanging
function
w.ok.enabled
app.activeDocument.hyperlinkTextDestinations.item

w.input.text
.isValid
w.show
w.input.text.length
app.activeDocument.hyperlinkTextDestinations.add
app.selection
0],    {name: w.input.text
If a window contains many elds it's often helpful to emphasise an edittext
control by changing its background color so that it's easier to spot. This, too, can
be done while the user enters data:
var
new
Window
'dialog'
w.group
w.add
'group'
w.group.add
'statictext {text: "Enter a number:"}'
w.input
w.group.add
'edittext {characters: 10, active: true, justify: "right"}'
w.buttons
w.add
'group {alignment: "right"}'

w.ok
w.buttons.add
'button {text: "OK", enabled: false}'

w.buttons.add
'button {text: "Cancel"}'
w.input.onChanging
function
var
valid
\d.,
$/.test
w.input.text
.graphics.backgroundColor
.graphics.newBrush
.graphics.BrushType.

SOLID_COLOR, valid
1, 1, 1, 1] : [1, 0.5, 0.5, 1]);   w.ok.enabled
valid
w.show
As soon as the user enters a character that's not a digit, dot, or comma, the
background is changed to red. When the illegal character is removed, the
window goes back to normal.
var
array
"one"
"two"
"three"
"thirty"
"hundred"
var
new
Window
"dialog"
"Drop-down select"
var
ddown
w.add
"dropdownlist"
, undefined, array
ddown.minimumSize.width
ddown.selection
ddown.active
var
buffer
ddown.onActivate
ddown.onDeactivate
function
buffer
ddown.addEventListener
"keydown"
function
k.keyName
"Backspace"

buffer
buffer.replace

k.keyName.length

buffer
k.keyName.toLowerCase
var
array.length
array
i].toLowerCase
.indexOf
buffer
array
i].toLowerCase
.indexOf
buffer

ddown.selection
w.add
"button"
, undefined,
"OK"
w.show
var
"one"
"two"
"three"
"thirty"
"hundred"
var
new
Window
"dialog"
"Drop-down select"
var
ddown
w.add
"dropdownlist"
, undefined, numbers
ddown.minimumSize.width
ddown.selection
ddown.active
var
buffer
ddown.
onActivate
function
buffer
ddown.addEventListener
"keydown"
function
buffer
k.keyName.toLowerCase
var
numbers.length
i].toLowerCase
.indexOf
buffer

i].toLowerCase
.indexOf
buffer

ddown.selection
w.add
"button"
, undefined,
"OK"
w.show
The script now remembers what we type in the variable called
buer
. When
the script starts, this variable is initialised to an empty string. The event listener
adds our input to the buer every time we press a key. Of course, when you
move away from the dropdown (by pressing Tab or clicking somewhere else in
the window) and then go back to the dropdown, you want to start afresh. That's
what the onActivate callback is for: when the dropdown is activated, the buer
is emptied.
The
dropdown's behaviour is now dierent. If you press
two
is highlighted as
before. But when you now type
, the script selects
three
in the list, not
hundred
as before.
There's one problem, though: you can't use the backspace key to correct
a typing error. That's because when you press any key, its name is appended
to the buer (except the Tab key). To correct an error, you need to move away
from the dropdown, go back to it, and start again. We would therefore like to
Macs there appear to be some problems with
event handler to the
dropdown list. These
problems can be avoided by adding the handler to
the window, though that in itself is not unproblematic.
See
https://forums.adobe.com/thread/
for
and the rst item starting with a t is displayed in the dropdown's control), but
unfortunately that doesn't work in ScriptUI. The remedy is to attach an event
listener to the drop-down that monitors keystrokes and selects the rst list item
var
"one"
"two"
"three"
"thirty"
"hundred"
var
new
Window
"dialog"
"Drop-down select"
var
ddown
w.add
"dropdownlist"
, undefined, numbers
ddown.minimumSize.width
ddown.selection
ddown.active
ddown.addEventListener
"keydown"
function
k.keyName.toLowerCase
var
numbers.length
i].charAt
.toLowerCase

i].charAt
.toLowerCase

ddown.selection
w.show
This mimics the behaviour of many dropdowns you encounter in InDesign but
also, for instance, on the web. If you type
two
is displayed in the list; if you
then type
hundred
is shown. In other words, any keypress matches just the
a general JavaScript issue. The script handles both bare numbers and numbers
followed by a measurement unit such as
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined,
"1 mm"
var
w.add
"edittext"
, undefined,
e1.characters
e2.characters
e1.active
function
handle_key
key, control
var
step
key.shiftKey
step
step
switch
key.keyName

"Up"
control.text
update
control.text, step
break

"Down"
control.text
update
control.text,
step

function
update
str, incr
try

var
array
str.split

var
String
array
0])+incr);  
array.length
array
1];}  
Keys have (among other things) a name (
Space
Minus
Shift
), an identier
(the hex value of the key in the form U+0000 or its name in the case of keys like
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined,
var
w.add
"edittext"
, undefined,
e1.characters
e2.characters
e1.active
function
handle_key
key, control
var
step
key.shiftKey
step
step
switch
key.keyName


"Up"
control.text
String
control.text
step
break

"Down"
control.text
String
control.text
step

// handle_key
e1.addEventListener
"keydown"
function
handle_key
k,
e2.addEventListener
"keydown"
function
handle_key
k,
w.show
The convoluted
String(Number(control.text)+step)
is necessary because we
can do arithmatic only with numbers while the edittext control accepts just text,
var
new
Window
"dialog"
var
buttongroup
w.add
"group"
var
buttongroup.add
, undefined,
"Buttons"
for
var

"button"
, undefined,
"Button "
var
buttongroup.add
, undefined,
"Knoppen"
for
var

"button"
, undefined,
"Button "
buttongroup.
addEventListener
'click'
, button_pressed
function
button_pressed
var
new
Window
"dialog"
var
w.add
"edittext"
edit.active
edit.characters
w.addEventListener
"keydown"
function
pressed
function
pressed
$.writeln
k.keyName
$.writeln
k.keyIdentifier
$.writeln
k.shiftKey
"Shift pressed"
"Shift not pressed"
$.writeln
k.altKey
"Alt pressed"
"Alt not pressed"
$.writeln
k.ctrlKey
"Ctrl pressed"
"Ctrl not pressed"
w.show
Event handlers
Event handlers are comparable to
callbacks in that they monitor what happens
in a dialog. They are more exible, though with this added exibility comes
some complexity. Event handlers are discussed from p. 149 of the Tools Guide.
Two examples here for illustration: one that monitors the mouse, another that
listens to the keyboard.
Monitoring the mouse
The rst example shows how to monitor specic
mouse events and some
environmental states:
var
new
Window
"dialog"
var
w.add
"button"
, undefined,
"Qwerty"
addEventListener
"click"
function
whatsup
function
whatsup
p.button
$.writeln
"Right-button clicked."
p.altKey
$.writeln
"Alt key pressed."
$.writeln
"X: "
p.clientX
$.writeln
"Y: "
p.clientY
w.show
The event handler monitors the mouse and the button and whenever you click
the button, it executes the function dened in the handler, and can be seen as
onClick
with some more possibilities.
The four properties whose value the script prints in the console are just
The second loop installs a callback for every button. These callbacks are
responsible for inserting the character associated with the pressed button. Note
that in its current form, the window is dismissed when you click a button. If you
would like the window to stay on the screen, all you have to do is to remove
w.close();
in the one-but-last line.
var
new
Window
"dialog"
var
w.add
"edittext"
var
w.add
"edittext"
e1.active
e1.characters
e2.characters
e1.onChanging
function
e2.text
e1.text
w.show
Now the second edit eld is lled while you type.
Lists, too, can be monitored. The following script displays a three-item list,
preselecting the rst item. Click a list item and it's name is printed in the console.
var
new
Window
"dialog"
var
w.add
"listbox"
, undefined,
"one"
"two"
"three"
list.selection
list.onChange
function
$.writeln
.selection.text
" selected."
w.show
Clicking anywhere in the list counts as a change in the list. Double-clicking is
often useful as well:
var
new
Window
"dialog"
var
w.add
"listbox"
, undefined,
"one"
"two"
"three"
list.selection
list.
onDoubleClick
function
$.writeln
.selection.text
" double-clicked."
w.show
Adding callbacks in loops
Windows
can be populated using loops. For example, you could add series
of buttons in a loop. Less intuitively, you can add callbacks in loops, too. The
following script exemplies this. It uses a loop to add a bunch of buttons to
a window, and then it supplements those buttons with a gaggle of callbacks.
The idea of the script is to facilitate entering accents from the range
Combining
diacritical marks
, and in eect the script is an extension, in a way, of the
Glyph panel. The Glyph panel can show several Unicode ranges, but not the
combining diacriticals, and as I found myself hunting down those diacritics
I thought it useful to have them in a panel.
The rst loop creates an object,
buttons
(Note: the convoluted w.separator.minimumSize.height = w.separator.
maximumSize.height is necessary because objects in ScriptUI don't have
var
new
Window
"dialog"
var
w.add
"button"
, undefined,
"Show this"
var
w.add
"button"
, undefined,
"Show that"
function
$.writeln
.text
" clicked."
function
$.writeln
.text
" clicked."
w.show
The script displays the dialog in the screenshot; press a button and it prints the
name of the button in the console.
The body of the callback's function – which for the b1 button in this example
{alert (this.text + " clicked.")}
– can be a function of any complexity. The
principle of the other callbacks is essentially the same.
Another frequent callback is
onChange
, which applies to several types of
control. The rst example shows how you can monitor an edit eld.
var
new
Window
"dialog"
var
w.add
"edittext"
var
w.add
"edittext"
e1.active
e1.characters
e2.characters
function
e2.text
e1.text
w.show
var
new
Window
"dialog"
w.alignChildren
"fill"
"fill"
var
w.add
"group"
g1.alignChildren
"fill"
"fill"
var

p1.preferredSize
[100, 50];
var
new
Window
"dialog"
var
w.add
"statictext"
, undefined,
"Static"
var
w.add
"edittext"
, undefined,
"Edit"
var
w.add
"button"
, undefined,
"Button"
// The window's backround
w.graphics.backgroundColor
w.graphics.newBrush
w.graphics.BrushType.SOLID_COLOR,
0.5, 0.0, 0.0]);   // Font and its colour for the first item, statictext
s.graphics.font
ScriptUI.newFont
var
new
Window
"dialog"
w.add
0,0,200,3]);   w.add
0,20,200,23]);   w.add
100,0,103,50]);w.show
You use it to apply a font to all elements in a window:
var
new
Window
"dialog"
var
group1
w.add
"group"
var
button1
group1.add
"button"
, undefined,
var
button2
group1.add
"button"
, undefined,
var
group2
w.add
"group"
var
button1
group2.add
"button"
, undefined,
var
button2
group2.add
"button"
, undefined,
button2.graphics.font
ScriptUI.newFont
"Verdana"
"Bold"
Both constructions can be used to change the typeface:
button2.graphics.font
"Verdana"
button2.graphics.font
ScriptUI.newFont
"Verdana"
var
ft
button2.graphics.font
button2.graphics.font
"Verdana-"
ft.style
ft.size
Note
For the font name you must use the font's PostScript name, which is not
necessarily the same as the menu name used in InDesign's or Photoshop's
app.fonts.item
"Gill Sans"
Note
ScriptUI recognises just four style names: Regular, Italic, Bold, and Bold-
Italic.
Note
font object has a (read-only) property
substitute
function
function
createMessageWindow
var
Window.find
var
new
Window
"dialog"
button1
w.add
"button"
, undefined,
"Default"
button2
w.add
"button"
, undefined,
button2.
graphics.font
"dialog:18"
w.show
button2.graphics.font
"Tahoma:18"
And to change the font style too, for example, to bold, use this construction:
button2.graphics.font
"Tahoma-Bold:18"
button2.graphics.font
ScriptUI.newFont
"dialog"
"Bold"
Note
: Fonts and colours
InDesign CC and later.
Font names are treated dierently on Macs and PCs
See Marc
function
writeConsole
txt
var
Window.find
With this script installed, whenever you select some text, the state of No break is
shown in the window: 0 if No break is not applied, 1 when it is applied, and 0/1
to indicate a mixed state.
Note
: to debug and edit a script that looks for an existing window, you need
to change the name on every new run because if you don't, the script uses the
Labels can be used on all types of control. For a special type of label –
see the section
var
windowName
'Attributes'
var
Window.find
// The original script
Labelling controls
Controls can be labelled so that you can later identify them. This works much
like using script labels on objects outside of ScriptUI. When you add a label to
a control, you in fact simply add a text property to it.
We saw an example earlier which dened two event listeners on two panels
with radio buttons so that it seemed as if those radio buttons were in one group.
This still required two listeners. I mentioned there that these panels could be
var
new
Window
"dialog"
var
radiogroup
w.add
"group"
var
radiogroup.add

for
var
"radiobutton"
, undefined,
"Rb "
var
radiogroup.add

for
var
"radiobutton"
, undefined,
"Rb "
panel1.children
0].value
radiogroup.addEventListener
"click"
function
event
// Slightly adapted from G. Singelmann's script, see
here
var
new
Window
"dialog"
var
maingroup
"panel {orientation: 'column'}"
add_row
maingroup
var
show_btn
"button"
, undefined,
"show"
show_btn.onClick
function
var
txt
for
var
maingroup.children.length
txt
maingroup.children
n].edit.text
"\n"
alert
"Rows: \n"
txt
win.show
function
add_row
maingroup
var
group
maingroup.add
"group"
group.edit
group.add
"edittext"
"    ", "    ", 200, 20], maingroup.children.length
group.plus
group.add
"button"
, undefined,
group.plus.onClick
group.minus
group.add
"button"
, undefined,
group.minus.onClick
group.index
maingroup.children.length
win.layout.layout
function
add_row
maingroup
function
maingroup.remove
.parent
win.layout.layout
Other aspects of windows, too, can be changed dynamically. On p. 114 is an
example of changing a container's orientation dynamically.
Control titles
So far we’ve added control titles by placing them in a separate staticText control,
as follows:
var
new
Window
'dialog'
var
grp
w.add
'group'
grp.add
'statictext'
, undefined,
'City: '
var
drop
grp.add
'dropdownlist'
, undefined,
'Lisbon'
'Lancaster'

drop.selection
w.show
var
new
Window
'dialog'
var
w.add
'listbox'
, undefined,
'one'
'two'
'three'
multiselect
var
select_all
w.add
'button'
, undefined,
'Select all'
select_all.onClick
function
var
selected
   for
var
list.items.length

selected
i] = list.items
i];   }   list.selection
selected
select_all.notify();
w.show
var
new
Window
"dialog"
var
grp
w.add
"group"
var
grp.add
"statictext"
, undefined,
var
txt
grp.add
"edittext"
txt.shortcutKey
"n"
var
w.add
"checkbox"
, undefined,
c1.shortcutKey
"c"
var
w.add
"checkbox"
, undefined,
"C&heck 1"
c2.shortcutKey
"h"
var
w.add
"radiobutton"
, undefined,
"&Radio 1"
r1.shortcutKey
var
w.add
"radiobutton"
, undefined,
r2.shortcutKey
"a"
w.show
Naturally, to make it clear to the user that certain shortcut keys can be used,
function
fix_measurement
n.replace
/ /g,
function
convert_units
n, to
var
unitConversions
'p'
'mm'
'in'
'ag'
'cm'
'c'
'tr'
var
fix_measurement
var
temp
obj.amount * unitConversions
obj.unit
/ unitConversions
CC, in /Adobe/Adobe ExtendScript Toolkit CC. This script is educational not only
because of the ashplayer control used in it.
(The ashplayer control was discontinued in
CC2017.)
Measurement control
var
new
Window
'dialog'
w.maximumSize.height
var
w.add
'panel {alignChildren: "left"}'
var
scrollGroup
panel.add
'group {orientation: "column"}'
for
var

scrollGroup.add
'statictext'
, undefined,
var
scrollBar
panel.add
'scrollbar {stepdelta: 20}'
// Move the whole scroll group up or down
scrollBar.onChanging
function
scrollGroup.location.y
.value
w.onShow
function
var
new
Window
"dialog"
"Butterfly"
var
w.add
"flashplayer"
, undefined,
File
"/d/scriptui/wave.swf"
w.show
The controls for stopping and starting movies in CS3 were discontinued in CS4.
You need
ActionScript and Flash/Flex to regain any control over movie clips. See
Loïc
Aigon's post at
here
for an interesting discussion on the interaction of Flash,
Flex, and ScriptUI.
The Object-Model Viewer in the ESTK is in fact a ashplayer control in a ScriptUI
window. See the script 35omvUI.jsx, which (in CS5/CS6 on Windows) lives in
Adobe/Adobe Utilities - CS5(CS6)/ExtendScript Toolkit CS5(CS6)/Required, from
var
panel.add
"scrollbar"
0,0,20,200], 0, 0, 60);where
are the default, minimum, and maximum values, respectively.
stepdelta
When you click an arrow button, the scrollbar's value changes by 1 by default.
So in a scrollbar which uses the default minimum and maximum of 0 and 100,
sbar.stepdelta
Now you need just ten clicks to move the slider from top to bottom. And with
a stepdelta of 100, one press moves the slider from the top to the bottom of the
scrollbar.
jumpdelta
The
jumpdelta = 50
witness the daunting code produced by Marc
var
new
Window
"dialog"
var
w.add
"group"
var
g.add
0,0,300,200], "Panel"
var
g.add
"scrollbar"
0,0,20,200]);w.show
var
new
Window
"dialog"
var
w.add
"group"
var
g.add
0,0,300,200]);   var
g.add
"scrollbar"
0,0,20,200]);   sbar.onChanging
function
$.writeln
sbar.value
w.show
sbar.value
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined, 50
var
w.add
, undefined, 50, 0, 100
slider.onChanging
function
e.text
slider.value
w.show
var
new
Window
'dialog'
var
value
w.add
'edittext {text: 0, characters: 3,
justify: "center", active: true}'
var
w.add
'slider {minvalue: -50, maxvalue: 50, value: 50}'
slider.onChanging
function
value.text
slider.value
value.onChanging
function
slider.value
value.text
w.show
You would think that
{minvalue: -50, maxvalue: 50, value: 0}
would place the
slider's handle in the slider's centre, but it doesn't, so you have to use 50 as the
start value. In the example we use an edittext control to display the slider's
var
new
Window
"dialog"
var
w.add
, undefined, 0, 100
slider.size
"width: 30, height: 300"
w.show
scrollbar
Scrollbars are added automatically to controls of type
edittext
listbox
when the text or the list items don't t their containers; see the examples on
pages11 and 29, respectively.
If you want to add scrollbars to any other control, you're very much on your
own in that you have to code all events yourself. This is not so straightforward,
to scale
var
new
Window
"dialog"
Image.prototype.onDraw
function
Note
: If an image does not redraw properly in
Photoshop CS5 or later, try using app.refresh();
This is part of Photoshop's object model, not
ScriptUI's.
change. (I don't know why it's necessary to do it like this, but it was the only way
to make it work; using
layout()
doesn't seem to work here.)
A small change in the denition of the listbox makes for a slightly dierent
apprearance of the window:
w.add
"listbox"
, undefined, array,
multiselect
By adding
{multiselect: true}
to the listbox denition, processed items remain
highlighted.
Counters as progress indicators
The
simplest progress indicator is a window that shows you the value of the
counter of a for-loop, for example. When I suspect that an operation may take
var
new
Window
"dialog"
var
new
Window
"dialog"
w.orientation
"row"
w.add
"progressbar"
, undefined, 0, 100
w.add
"progressbar"
, undefined, 0, 100
w.add
"progressbar"
, undefined, 0, 100
pb1.preferredSize
pb2.preferredSize
pb3.preferredSize
20, 300];   pb1.value
pb2.value
pb3.value
w.show
There are more sophisticated ways of applying progress bars, of which Marc
var
"one"
"two"
"three"
"four"
"five"
var
hlights
highlight_list
for
var
list.length
hlights.children
0].selection
hlights.show
// user functions
hlights.close
function
highlight_list
array
var
new
Window
Note
: On Mac OS the
Mondo rendering engine was
introduced in
Photoshop CC 2015. As a result, JPG
images are no longer accepted, all images must be PNG.
According to Davide
Barranca this will be xed (see
cc20
5-survival-guide
, point8).
progressbar
The
progressbar
control, unsurprisingly, is used to display a progress bar so that
w.add
"progressbar"
, undefined, start, stop
start
stop
are the start and stop values of the bar itself,
corresponding to the rst and last items of whatever you're processing. The start
value will usually be 0, while stop could be, for instance, the index of last array
element if you're dealing with an array. Here is an example:
var
found
new
Array
var
new
Window
for
var
found.length
w.pbar.value
found.length
Mac you can create
vertical
progress bars simply by making their width
smaller than their height. Unfortunately, on PCs running
Windows this isn’t
possible (you can create a vertical bar, but the progress indication will always be
left-to-right).
Note: in scripts that use
w.tabs
2] = w.tabGroup.add
'group'

w.tabs
2].add ('statictext {text: "UI Scaling"}'

w.tabs
2].add ('panel');  
w.tabs
2].add ('panel {text: "Options", preferredSize: [-1, 200]}'
w.buttons
w.add
'group {alignment: "right"}'
w.buttons.add
'button {text: "OK"}'
w.buttons.add
'button {text: "Cancel"}'
for
var
w.tabs.length
w.tabs
i].orientation
'column'
w.tabs
i].alignChildren
'fill'
w.tabs
i].alignment
'fill'
'fill'
w.tabs
i].visible = false;   }      w.stubs.onChange
showTab
function
showTab
w.stubs.selection

for
var
w.tabs.length

w.tabs
i].visible = false;  

w.tabs
w.stubs.selection.index
w.onShow
function
w.stubs.selection
showTab
w.show
Vertical tabs
ScriptUI doesn't natively support the kind of vertically tabbed windows that you
see in InDesign. Examples of such windows are InDesign's Preferences window
and the paragraph and character style windows. But using a combination of of
the properties
visible, that type of window is not dicult to emulate.
The following script mimics (part of) InDesign's Preferences window.
The idea is to create a group or a panel for each tab and stack align them so that
they're all in the same location in the window. An onChange event handler on
the list makes all 'tabs' (groups/panels) invisible, then makes the selected tab
visible.
var
new
Window
'dialog {text: "Preferences", orientation: "column", alignChildren:

["fill","fill"], properties: {closeButton: false}}
w.main
w.add
'group {preferredSize: [600, 500], alignChildren: ["left","fill"]}'
w.stubs
w.main.add
'listbox'
, undefined,
'General'
'Interface'
'UI Scaling'
w.stubs.preferredSize.width
w.tabGroup
w.main.add
'group {alignment: ["fill","fill"], orientation: "stack"}'
w.tabs
   w.tabs
0] = w.tabGroup.add
'group'

w.tabs
0].add ('statictext {text: "General"}'

w.tabs
0].add ('panel');  
w.tabs
0].add ('checkbox {text: "Show Start workspace when no documents are open"}'

w.tabs
0].add ('checkbox {text: "Show Recent Files workspace when opening a file"}'

w.tabs
0].add ('panel {text: "Page numbering", preferredSize: [-1, 80]}'

w.tabs
0].add ('panel {text: "Font downloading and embedding", preferredSize: [-1, 80]}'

w.tabs
0].add ('panel {text: "Object editing", preferredSize: [-1, 150]}'

w.tabs
0].add ('panel {text: "When placing or pasting content", preferredSize: [-1, 80]}'

w.tabs
0]) {  
'group {alignment: "center"}'

Two examples of treeview controls are
Gabe
Harbs's script
that shows based-on
var
new
Window
"dialog"
"Export XML"
, undefined,
closeButton
w.alignChildren
"right"
var
w.add
tpanel.alignChildren
"fill"
"fill"
tpanel.preferredSize
350,300];   var
general
tpanel.add
, undefined,
"General"

general.alignChildren
"fill"

var
general.add
, undefined,
"Options"

g_options.alignChildren
"left"

g_options.dtd_decl
g_options.add
"checkbox"
, undefined,
"Include DTD Declaration"

g_options.view_XML
g_options.add
"checkbox"
, undefined,
"View XML Using: "

g_options.export_sel
g_options.add
"checkbox"
, undefined,
"Export From Selected Element"

g_options.export_untagged
g_options.add
"checkbox"
, undefined,
"Export Untagged Tables as CALS XML"

g_options.remap
g_options.add
"checkbox"
, undefined,
"Remap Break, Whitespace, and Special Characters"

g_options.xslt
g_options.add
"checkbox"
, undefined,
"Apply XSLT: "

g_options.add
"statictext"
, undefined,
"Encoding: "
var
tpanel.add
, undefined,
"Images"

images.alignChildren
"fill"

var
images.add
, undefined,
"Image Options"
var
buttons
w.add
"group"
buttons.add
"button"
, undefined,
"Export"
"ok"
buttons.add
"button"
, undefined,
"Cancel"
w.show
Tabs can be preselected just like items in a list. For example, the above script
starts with the General tab selected; to open the Images tab on start-up, use this
tpanel.selection
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 250]);   var
tree.add
"node"
"Mammals"

mammals.cats
mammals.add
"node"
"cats"

mammals.cats.add
"item"
"tabbies"
mammals.cats.add
"item"
"tiggers"

mammals.dogs
mammals.add
"node"
"dogs"

mammals.dogs.add
"item"
"terrier"

mammals.dogs.collies
mammals.dogs.add
"node"
"colly"

mammals.dogs.collies.add
"item"
"border"

mammals.dogs.collies.add
"item"

mammals.dogs.add
"item"
"labrador"
var
insects
tree.add
"node"
"Insects"

insects.add
"item"
"ants"
insects.add
"item"
insects.add
"item"
"flies"
w.add
"button"
, undefined,
"Write XML"
xml.onClick
exportXML
function
exportXML
$.writeln
'?xml version="1.0" encoding="UTF-8" standalone="y&#x?xml;&#x v11;&#x ers;&#xion=;&#x"1.0;&#x" en;Æ o; ing;&#x="UT;-8";&#x sta;&#xndal;&#xone=;&#x"-14;&#x.9 y;.9;&#x es";&#x?000;es"?\rTreeV&#xT48 ;&#xr11 ;îV1; ie;&#xw000;iew'
for
var
tree.children.length

writeXML
tree.children
i], 1);   $.writeln
"/TreeV&#x/T48;&#x r11;&#x eeV; i;w00;iew"
function
writeXML
node, level
$.writeln
indent
level
node.text
var
kids
node.items
for
var
kids.length

kids
i].type
"node"

writeXML
kids
i], level


$.writeln
indent
level
"it&#xit7 ;m00;em"
kids
i].text
"/it&#x/it7;&#x em0;em"
// for
$.writeln
indent
level
node.text
function
indent
var
for
var
?xml version="1.0" encoding="UTF-8" standalone="y&#x?xml;&#x v10;&#x ers;&#xion=;&#x"180;&#x.1 .;�" e;&#xnc6.; od;&#xing=;&#x"UTF;&#x-8" ;&#xstan;Úlo;&#xne=";&#x-20.; y1;� es;&#x"?00;es"?
TreeV&#xT45 ;&#xr10 ;îV1; ie;&#xw000;iew
M&#xM-6 ; mma;&#xls00;ammals
caತ.; ts;ts
it&#xit6 ;m00;emtabbies/it&#x/it6;&#x.1 e;&#xm000;em
it&#xit6 ;m00;emtiggers/it&#x/it6;&#x.1 e;&#xm000;em
/ca&#x/ca4;&#x.1 t;&#xs000;ts
it&#xit6 ;m00;emterrier/it&#x/it6;&#x em0;em
cÆ o;&#xlly0;olly
it&#xit6 ;m00;emborder/it&#x/it6;&#x.1 e;&#xm000;em
it&#xit6 ;m00;emhighland/it&#x/it6;&#x.1 e;&#xm000;em
/c&#x/c6 ;&#xolly;olly
it&#xit6 ;m00;emlabrador/it&#x/it6;&#x em0;em
/M&#x/M-6;&#x amm; ls0;ammals
Insec&#xI-10;&#x nse; -13;&#x ts0;ts
it&#xit6.; em;emants/it&#x/it6;&#x em0;em
it&#xit6.; em;embees/it&#x/it6;&#x em0;em
it&#xit6.; em;emies/it&#x/it6;&#x em0;em
/Insec&#x/I-1;� ns;ì-1; ts;ts
/TreeV&#x/T45;&#x r10;&#x eeV; i;w00;iew
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 150]);   var
tree.add
"node"
"Mammals"
mammals.add
"item"
"cats"
mammals.add
"item"
"dogs"
var
insects
tree.add
"node"
"Insects"
insects.add
"item"
"ants"
insects.add
"item"
insects.add
"item"
"flies"
mammals.
expanded
insects.expanded
var
insert_btn
w.add
"button"
, undefined,
"Insert item"
insert_btn.onClick
function
tree.selection.parent.add
"item"
"Reptiles"
, tree.selection.index
w.show
Elements are added within their branch. If you select a node, the added element
is inserted at the level of that node but as an item, as shown in the screenshot
next to the script code. To insert that element as a node, you need to check the
current selection’s type. The following context-sensitive function inserts an
element of the correct type at each level:
insert_btn.onClick
function
tree.selection.parent.add
tree.selection.type,
"Reptiles"
, tree.selection.index
Writing a treeview as XML
It will be clear by now that any form of
tree-processing will have to be done by
recursive functions. The
expand_all
move_up
functions shown earlier are
examples. Another example would be to write out a treeview as an XML le.
Here is an example – the panel on the right shows the script’s output:
In CC and later, adding an item collapses the selection's parent. To x
that, add these two lines so that the callback looks as follows:
insert_btn.onClick
function
tree.selection.parent.add
"item"
"Reptiles"
, tree.selection.index
tree.selection.parent.expanded
tree.selection.parent.expanded
tree.onChange
function
tree.selection.type
"node"

remove_btn.enabled

remove_btn.enabled
remove_btn.onClick
function
tree.remove
tree.selection
As you can see in the screenshot, when you select a node in the tree, the
Remove item
button is disabled. There is therefore now no need to do any
cats
Insects
ants
Within the treeview, Mammals has index 0, Insects has index 1. Within Mammals,
cats is 0; within Insects, ants is 0. To insert an item you must therefore address
the correct parent node. Using the structure in our example, that can be done
as follows:

If the selecion is an item and the thing above it is a node, then the script
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 100, 150]);   var
tree.add
"node"
"Mammals"

mammals.add
"item"
"cats"

mammals.add
"item"
"dogs"
var
insects
tree.add
"node"
"Insects"

insects.add
"item"
"ants"

insects.add
"item"

insects.add
"item"
"flies"
mammals.expanded
insects.expanded
var
remove_btn
w.add
"button"
, undefined,
"Remove item"
remove_btn.onClick
function
tree.selection.type
"node"

tree.remove
tree.selection
w.show

var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 250]);   var
tree.add
"node"
"Mammals"

mammals.cats
mammals.add
"node"
"cats"

mammals.cats.add
"item"
"tabbies"

mammals.cats.add
"item"
"tiggers"

mammals.dogs
mammals.add
"node"
"dogs"

mammals.dogs.add
"item"
"terrier"

mammals.dogs.collies
mammals.dogs.add
"node"
"colly"

mammals.dogs.collies.add
"item"
"border"

mammals.dogs.collies.add
"item"

mammals.dogs.add
"item"
"labrador"
var
insects
tree.add
"node"
"Insects"

insects.add
"item"
"ants"

insects.add
"item"

insects.add
"item"
"flies"
w.add
"button"
, undefined,
"Up"
up.onClick
MoveUp
function
MoveUp
tree.selection.index


var
tree.selection

var
previous
sel.parent.items
sel.index

sel.type
"item"
previous.type
"item"

swap
sel, previous
tree.selection
previous

var
search_button
w.add
'button {text: "Search"}'
search_button.onClick
function
var
items
find_item
tree,
, srch.text
items.length
// Nothing found

tree.selection

The buildTree() function creates a tree that represents the paragraph-style
structure of the active document. This is the same document we used for the
script on p. 49 that creates a dropdownlist on the y.
Finding and highlighting items in a tree
To nd an
item in a tree, we need to
traverse the tree. The following script
denes a function
nd_item()
, which is a traditional recursive function, very
similar to functions that traverse folders and XML structures. The function
Creating a tree on the y
In addition to predening treeviews in a script, trees can be created dynamically
from some structure, e.g.
paragraph styles in style groups. The following script is
an example.
function
var
new
Window
'dialog'
var
tree
w.add
'treeview'
0, 0, 150, 350]);   var
tree.add
'node'
'Mammals'
mammals.cats
mammals.add
'node'
'cats'

mammals.cats.add
'item'
'tabbies'

mammals.cats.add
'item'
'tiggers'
mammals.dogs
mammals.add
'node'
'dogs'

mammals.dogs.add
'item'
'terrier'

mammals.dogs.collies
mammals.dogs.add
'node'
'colly'

mammals.dogs.collies.add
'item'
'border'

mammals.dogs.collies.add
'item'

mammals.dogs.add
'item'
'labrador'
var
insects
tree.add
'node'
'Insects'
insects.add
'item'
'ants'
insects.add
'item'
insects.add
'item'
'flies'
tree.onDoubleClick
function
tree.selection.type
'node'

expand_node
tree.selection
function
expand_node
tree
tree.expanded
var
branches
tree.items
for
var
branches.length

branches
i].type
'node'

expand_node
branches
i]);  
w.onShow
function
expand_node
tree
w.show
Without the onShow callback
With the onShow callback
they are double-clicked – can be handled by one function which is called in two
dierent ways: by an
onShow()
callback when the dialog is drawn and by an
event listener when a node is double-clicked.
The function
expand_node()
Images in treeviews
As in lists, you can add an image to nodes and items, as in the following script:
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 200]);   var
folder_1
tree.add
"node"
"Folder 1"
folder_1.
File
"/d/scriptui/folder_icon.idrc"
folder_1.add
"item"
"File 1 1"

folder_1.items
0].image = File
"/d/scriptui/file_icon.idrc"
folder_1.add
"item"
"File 1 2"

folder_1.items
1].image = File
"/d/scriptui/file_icon.idrc"
folder_1.add
"item"
"File 1 3"

folder_1.items
2].image = File
"/d/scriptui/file_icon.idrc"
var
folder_2
tree.add
"node"
"Folder 2"
folder_2.image
File
"/d/scriptui/folder_icon.idrc"
folder_2.add
"item"
"File 2 1"
folder_2.add
"item"
"File 2 2"
folder_2.add
"item"
"File 2 3"
mammals.expanded
insects.expanded
The
expanded
property expands the node to show just its items, but any
subnodes aren’t expanded. This expands the whole tree because each top-
level node contained just items, not any subnodes. What we need therefore is
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 150]);   var
tree.add
"node"
"Mammals"
mammals.add
"item"
"cats"
mammals.add
"item"
"dogs"
var
insects
tree.add
"node"
"Insects"
insects.add
"item"
"ants"
insects.add
"item"
insects.add
"item"
"flies"
mammals.expanded
insects.expanded
w.show
Nodes are collapsed by default (they are distinguished from items by the +
or  shown before them up to CS6, by little triangles in CC). To expand a node,
double-click it or single-click the plus that precedes it. To expand any node
when the window is drawn, use
myNode.
expanded = true
as shown in the
example.
Nodes can be embedded under nodes to create multi-level trees. Here is an
example:
var
new
Window
"dialog"
var
tree
w.add
"treeview"
0, 0, 150, 250]);   var
tree.add
"node"
"Mammals"
mammals.cats
mammals.add
"node"
"cats"

mammals.cats.add
"item"
"tabbies"

mammals.cats.add
"item"
"tiggers"
mammals.dogs
mammals.add
"node"
"dogs"

mammals.dogs.add
"item"
"terrier"

mammals.dogs.collies
mammals.dogs.add
"node"
"colly"

mammals.dogs.collies.add
"item"
"border"

mammals.dogs.collies.add
"item"

mammals.dogs.add
"item"
"labrador"
var
insects
tree.add
"node"
"Insects"
insects.add
"item"
"ants"
insects.add
"item"
insects.add
"item"
"flies"
w.show
InDesign up to CC
InDesign from CC
function
var
"Annabel"
"Bertie"
"Caroline"
"Debbie"
"Erica"
var
new
Window
"dialog"
"Place documents"
, undefined,
closeButton
w.alignChildren
"right"
var
w.add
"group"
"statictext"
, undefined,
"Folder: "
var
group
"group {alignChildren: 'left', orientation: 'stack'}"
File
.fs
"Windows"

var
group.add
"dropdownlist"
, undefined, names

var
group.add
"edittext"

var
group.add
"edittext"

var
group.add
"dropdownlist"
, undefined, names
e.text
0]; e.active
list.preferredSize.width
e.preferredSize.width
e.preferredSize.height
var
buttons
w.add
"group"
buttons.add
"button"
, undefined,
"OK"
buttons.add
"button"
, undefined,
"Cancel"
list.onChange
function
e.text
list.selection.text
e.active
w.show
You can see how it works when you remove the
stack orientation: the edittext
control and the dropdown list are then displayed separately.
Creating lists on the y
In the examples given so far, we predened lists in the form of an array (["one",
"two", "three"], ["Annabel", "Bertie", . . .]). Another way of creating a dropdown
is creating it on the y. I've used this approach to present a list of styles that
includes paragraph style groups.
The following script uses a function (
buildList()
) recursively to create a list of
paragraph style names with their path names, so to speak. The list's format is
that of InDesign's format in the Table of Contents window.
Edit elds with dropdowns
useful list type which isn't available in ScriptUI is one that can be called
‘editable dropdown’, or perhaps ‘edit eld with a dropdown attached’. Examples
are the Find What eld in the Find/Change dialog and most elds in the
You can check which item is
selected using the item's text property:
myChoice
myDropdown.selection.text
You can also obtain the item's index:
myChoice
myDropdown.selection.index
As with list boxes, in dropdown lists you can add
images to list items:
myDropdown.items
0].image = myImage
var
new
Window
"dialog"
var
myDropdown
w.add
"dropdownlist"
, undefined,
"one"
"two"
"three"
myDropdown.selection
w.show
The separator counts as a list item, so
myDropdown.items.length
var
new
Window
"dialog"
var
myDropdown
w.add
"dropdownlist"
, undefined,
"one"
"two"
"three"
myDropdown.add
"separator"
, undefined, 2
myDropdown.selection
w.show
In this example the separator is added before the third item in the list. Note that
you must use
as a dummy argument: the insertion point must the
the third argument of the
add()
Clicking an a control to update it is not particularly good. But I was reminded
of some code that Marc
var
new
Window
'dialog'
w.list
w.add
'listbox'
, undefined,
'one'
'two'
'three'
var
w.add
'button {text: "Update"}'
b.onClick
function
for
var
w.list.items.length

w.list.items
i].text
parseInt
app.version

refresh
w.list
function
refresh
control
var
control.size
control.size
1+wh[0], 1+wh[1]];   control.size
wh[0], wh[1]];   }w.show
In
Windows 10, listboxes (and therefore multi-column lists too) stopped working
in CS6 and earlier.
dropdownlist
Dropdown lists are similar to listbox lists in many respects; the main dierences,
naturally, is that you can see one item at a time if the list is not selected and that
you can select just one item at a time. Apart from that, they are processed in
much the same way as list boxes. Here is an example:
var
new
Window
"dialog"
var
myDropdown
w.add
"dropdownlist"
, undefined,
"one"
"two"
"three"
myDropdown.selection
w.show
entry.onChanging
function
var
temp
entry.text,
tempArray
   for
var
array.length
array
i].toLowerCase
.indexOf
temp

tempArray.push
array
i]);   if (tempArray.length
// Create the new list with the same bounds as the one it will replace
tempList
w.add
"listbox"
, list.bounds, tempArray,
scrolling
w.remove
tempList
list.selection
// entry.onChanging
var
new
Window
'dialog'
w.list
w.add
'listbox'
, undefined,
'one'
'two'
'three'
var
w.add
'button {text: "Update"}'
b.onClick
function
for
var
w.list.items.length

w.list.items
i].text
w.show
The script displays a list with three items and a button. If you click the button
the script replaces the text strings in the list items with '0' – that, at least, is the
intention. But in CC and later (up to CC2015 at the moment of writing) that
doesn't work any longer. To update the list's display you need to click on it.
entry.onChanging
function

temp
.text.slice
.text
.text

selected
  
list.selection

for
var
animals.length

i].toLowerCase
.search
temp

selected.push



list.selection
selected
Now if you enter
, both dogs and cats and dogs are selected; but when you
enter
, only dogs is highlighted. Sinilarly, when you enter
, all items that
contain a digit are selected. The range of special symbols is restricted; you can
and ( cause a syntax error.
picked
type_ahead
'bat'
'beaver'
'bee'
'cat'
'cats and dogs'
'dog'
'moose'
'moth'
'mouse'
function
type_ahead
var
selected, temp
var
new
Window
'dialog {text: "Quick select", alignChildren: "fill"}'
var
selected
   var
entry
w.add
'edittext {active: true}'
var
w.add
'listbox'
0,0,150,250], animals,
multiselect
entry.onChanging
function

temp
.text

selected
  
list.selection

for
var
animals.length

i].toLowerCase
.indexOf
temp

selected.push



list.selection
selected
w.add
'button {text: "Ok"}'
w.show
selected
   for
var
list.selection.length

selected.push
list.selection
i].text
picked
type_ahead
'bat'
'beaver'
'bee'
'cat'
'cats and dogs'
'dog'
'moose'
'moth'
'mouse'
function
type_ahead
var
new
Window
'dialog {text: "Quick select", alignChildren: "fill"}'
var
entry
w.add
'edittext {active: true}'
var
w.add
'listbox'
0, 0, 150, 250], animals);  
list.selection
entry.onChanging
function

var
temp
.text

list.removeAll

for
var
animals.length

i].toLowerCase
.indexOf
temp

list.add
'item'
i]);  


list.items.length

list.selection

In an earlier version of this guide, this script used the line
entry.
function
w.close
var
new
Window
"dialog"
w.spacing
var
w.add
"group"
headers.spacing
headers.margins
0,5,0,0];   var
0,0,100,20];   headers.add
"statictext"
"\u00A0French"
headers.add
"statictext"
"\u00A0English"
headers.add
"statictext"
"\u00A0Dutch"
headers.graphics.backgroundColor
w.graphics.newBrush

w.graphics.BrushType.SOLID_COLOR,
0.7,0.7,0.7], 1);   for
var
headers.children.length

headers.children
i].graphics.font
ScriptUI.newFont
"Arial"
var
columns
w.add
"group"
columns.spacing
var
0,0,100,200];   var
col1
columns.add
"listbox"
"Un"
"Deux"
"Trois"
var
col2
columns.add
"listbox"
"One"
"Two"
"Three"
var
col3
columns.add
"listbox"
"Een"
"Twee"
"Drie"
w.show
myList.add
"item"
"One"
subItems
0].text
"Un"
subItems
0].image = myFile_1
subItems
1].text
"Een"
subItems
1].image = myFile_2
Tables
Multi-column lists aren't really
tables in that you can't select individual cells in
a row: whichever element you click always selects the whole row. But you can
fake a table by placing several list boxes next to each other without any space
var
new
Window
"dialog"
var
columns
w.add
"group"
columns.spacing
var
numberOfColumns
1, showHeaders
, columnWidths
80]};   header.columnTitles
"French"
var
col1
columns.add
"listbox"
, undefined,
"Un"
"Deux"
"Trois"
header.columnTitles
"English"
var
col2
columns.add
"listbox"
, undefined,
"One"
"Two"
"Three"
header.columnTitles
"Dutch"
var
col3
columns.add
"listbox"
, undefined,
"Een"
"Twee"
"Drie"
w.show
Now you can select individual cells. In addition, you now have some control
over the appearance of individual columns (type, typesize, foreground and
Multi-column lists
Using
multi-column
lists you can create table-like structures
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,

numberOfColumns
showHeaders

columnTitles
"English"
"French"
"Dutch"
myList.add
"item"
"One"
subItems
0].text
"Un"
subItems
1].text
"Een"
myList.add
"item"
"Two"
subItems
0].text
"Deux"
subItems
1].text
"Twee"
myList.add
"item"
"Three"
subItems
0].text
"Trois"
subItems
1].text
"Drie"
w.show
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
numberOfColumns
3, showHeaders

columnTitles
"English"
"French"
"Dutch"

columnWidths
30,30,100]});Columns can be resized in the normal way: move the mouse cursor over
a column separator in the header row (the cursor changes to
) and drag the
column to the desired width.
Images can be added to any of the items in any of the columns:
Note
: like listboxes, in InDesign CS6 on
Windows10,
multi-column
listboxes
should be placed in a group or a panel.
Note
: Multi-column lists with column headers cause
Illustrator CS6 on the Mac to crash. CS5.5 and earlier
and CC and later are ne, as are all versions on
Windows. See
this forum thread
Including images in a list
List items can include images; here is an example:
var
"Footnotes"
"Masters"
"Locked stories"
var
"footnotes.idrc"
"masters.idrc"
"locked_stories.idrc"
var
new
Window
"dialog"
var
myList
w.add
"listbox"
for
var
descriptions.length
myList.add
"item"
i]);   myList.items
i].image = File
"~/Desktop/"
i])   }w.show
The rst two lines create arrays of image names and list-item texts; the for-loop
then adds list items and adds images to each item. (Like icons in icon buttons,
images should be in PNG, IDRC, or JPG format.)
Adding checkmarks
You can add
var
new
Window
"dialog"
var
w.add
"listbox"
, undefined,
"One"
"Two"
"Three"
"Four"
list.items
1].checked
w.show
var
new
Window
"dialog"
var
w.add
"listbox"
, undefined,
"One"
"Two"
"Three"
"Four"
for
var
list.items.length
list.items
i].checked
list.items
1].checked
w.show
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined, undefined,
multiselect
for
var
myList.add
"item"
String
myList.preferredSize
100,200];      var
w.add
"button"
, undefined,
"Select"
b.onClick
function
myList.selection
50, 51, 52, 53, 54];   }w.show
The problem is clear. ScriptUI’s default behaviour is to scroll a list so that
a selected item is shown. But in multiselect lists in which more than two items
are selected, only the rst two items in the selection are shown. To remedy
this and show all selected items, we do a
revealItem()
on the last item of the
selection. If that’s handled by a separate function then other processes can
make use of that same function:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined, undefined,
multiselect
for
var
myList.add
"item"
String
myList.preferredSize
100,200];      var
w.add
"button"
, undefined,
"Select"
b.onClick
function
myList.selection
50,51,52,53,54];}   myList.onChange
ShiftList
function
ShiftList
.selection


var
.selection.pop
.index

.items.length

.revealItem

w.show
selecting it, use
revealItem()
; in screenshot (c) an item is displayed (Line_50)
without selecting it. These three options are shown in the following script:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
for
var
myList.add
"item"
String
myList.preferredSize
100,100];   w.onShow
function
//myList.selection = 50; // screenshot (b)
//myList.revealItem ("Line_50"); // screenshot (c)
w.show
As the script stands it displays window (a); uncomment
myList.selection = 50;
and the script shows window (b); comment out that line again and uncomment
list.revealItem ("Item_50");
to show window (c).
myList.revealItem
list.items.length
myList.revealItem
list.revealItem
Finally,
revealItem()
can be used to create a workaround for a display bug in
multiselect lists in InDesign before CC. The bug is shown by the following script:
(b)
Note
: In CC and later, selecting or
revealing list items must be
onShow callback. Another dierence is that in CC,
the selected or revealed item appears at the top of the list box,
not at bottom as in CS6.
Removing items from a list
To remove an item from a list, use the
.remove()
myList.remove
myList.items
myList.remove
myList.find
"two"
Removing items from a multi-selection list
To remove any selected items from a multi-selection
var
new
Window
"dialog"
var
w.add
"listbox"
, undefined,
"one"
"two"
"three"
"four"
"five"
multiselect
var
w.add
"button"
, undefined,
var
new
Window
"dialog"
"Rearrange"
var
w.add
"listbox"
, undefined,
"one"
"two"
"three"
"four"
"five"
multiselect
var
w.add
"button"
, undefined,
"Up"
var
down
w.add
"button"
, undefined,
"Down"
up.onClick
function
var
list.selection
0].index
contiguous
list.selection
The
down
functions are almost the same. When we move selected items
up, we rst check that the rst selected item is not the rst item in the list. We
then basically percolate the name of the item preceding the rst selected item
down through the list until it follows the last selected item. We then need to
adjust the displayed selection. Moving items down follows the same principle.
var
new
Window
"dialog"
"Rearrange"
var
w.add
"listbox"
, undefined,
"one"
"two"
"three"
"four"
"five"
list.selection
var
w.add
"button"
, undefined,
"Up"
var
down
w.add
"button"
, undefined,
"Down"
up.onClick
function
var
list.selection.index


swap
list.items
n-1], list.items
n]);  
list.selection

down.onClick
function
var
list.selection.index
list.items.length


swap
list.items
n], list.items
n+1]);  
list.selection

function
swap
var
temp
x.text
x.text
y.text
y.text
temp
w.show
Actually, the list items themselves remain where they are: it's their text
properties that are swapped in the function
swap()
Moving list items (multi-selection lists)
Moving a multiple selection is a bit more involved. In the previous selection we
saw that to move a list item is to swap its name with the preceding or following
item's name. The same approach is used to move a multiple selection (see the
script on the next page).
var
new
Window
"dialog"
var
myList
w.add
"listbox"
0, 0, 50, 150], ["A"
"K"
var
w.add
"edittext"
input.active
var
w.add
"button"
, undefined,
"Insert"
"ok"
b.onClick
function
insert_item
myList, input.text
input.text
input.active
w.show
function
insert_item
list_obj, new_item
list_obj.find
new_item
var
stop
list_obj.items.length
var
stop
new_item
list_obj.items
i].text

list_obj.add
"item"
, new_item, i
The script's interface is a bit klunky, and as we named the Insert button
responds to the Enter key – triggering the onClick handler – so it sits there just
catching Enter key presses. Later on we'll handle such situations more elegantly
by dening an event handler rather than using a button for this purpose.
Moving list items (single-selection lists)
To
move items around in a list, we need two buttons: one to move the selected
list item up, the other to move it down. We also need a function to swap two
adjacent list items. Here is a simple example:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"cat"
"dog"
"cat"
"mouse"
multiselect
var
w.add
"button"
, undefined,
"Select cats"
find.onClick
function
var
found
   for
var
myList.items.length

myList.items
i].text
"cat"

found.push
myList.selection
found
w.show
Inserting items into a list
We saw earlier that
items can be added to an existing list using the
myList.add
"item"
"zero"
To avoid
creating duplicate entries in a list, you can use the
myList.find
myNewItem
myList.add
"item"
, myNewItem
If you add an item to a list, the window is updated automatically, as shown by
this script:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
var
w.add
"button"
, undefined,
"Add"
b.onClick
function
myList.
"item"
"zero"
w.show
(As you can see, when the list grows out of its box, ScriptUI adds a scrollbar.)
Keeping a list sorted
Here is another example of list processing, this time inserting an item in a list
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
"four"
multiselect
var
print
w.add
"button"
, undefined,
"Print selected items"
print.onClick
function
for
var
myList.selection.length

$.writeln
myList.selection
i].text
w.show
Finding items in a list
To nd an item in a list, use the
var
myItem
myList.find
"two"
var
new
Window
"dialog"
var
"one"
"two"
"three"
"four"
"five"
var
myList
w.add
"listbox"
, undefined, numbers,
multiselect
myList.selection
myList.find
"two"
myList.selection
myList.find
"four"
w.show
Note that
nd()
myList.onChange
function
myList.selection
myList.selection
myList.prevSel
myList.prevSel
myList.selection.index
Finding out which item is selected in multi-select lists
Selections in multi-select
lists are a bit dierent in that they're arrays of list items.
We'll amend slightly a previous script:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
multiselect
myList.onChange
function
$.writeln
myList.selection.constructor.name
w.show
Run the script, select any two items, and the script prints
Array
in the console.
This is the case even if the selection consists of one item.
Processing lists
Lists are arrays of ListItems. They are processed a bit dierently than standard
arrays. The following script processes a list simply by printing the text attribute
of each item:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
var
print
w.add
"button"
, undefined,
"Print"
print.onClick
function
for
var
myList.items.length

$.writeln
myList.items
i].text
w.show
As we saw earlier, in multi-select
lists, selections are arrays. Lists themselves are
arrays, so selections are sub-arrays of lists. This can be shown by the following
script, which prints
three
in the console:
the result is
. The reason is that myList.selection is not text, but a
listItem
object. Amend the script as follows:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
myList.onChange
function
$.writeln
myList.selection.
constructor.name
w.show
Run the script again and click an item; the script now prints
ListItem
myList.selection.text
"two"
Another useful property of list items is
index
myList.selection.index
Note
: before processing a list item, you should always check if anything is
selected in the list:
myList.onChange
function
myList.selection
$.writeln
myList.selection.constructor.name
This goes for the other types of list, too – dropdown and treeview, see below.
(The example may look odd in that
onChange
is triggered if you make
a selection in a list, but there are other situations where you access a list and
then it's necessary to check if any item is selected. It is therefore a good habit
always to check the list's selection status.)
Forcing a list selection
Even if you select a list item when the dialog is drawn, a user can deselect the
list's selection. To make sure that there is always a selection in a list, you can
monitor the list and select an item just in case the selection becomes null. My
collegue Vlad
Vladila suggested the following function:
myList.selection
0,2];This selects items 0 and 2. To select a number of consecutive items you need to
myList.selection
0,1,2];selects the rst three items in myList.
Note
: making selections in a list adds to any existing selection. For instance,
myList.selection
0,1];myList.selection
2];select three items in the list. To avoid adding to a list’s existing selection, start
with making the selection null:
myList.selection
myList.selection
2];Finding out which item is selected
In a
mySelection
myList.selection
To make visible what we do in our example script, we’ll use here another
callback,
onChange, which responds to changes to a window’s control. We’ll
add a callback to our example script that monitors the listbox:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
myList.
function
$.writeln
myList.selection
w.show
Run the script, click, say "two", and the script will print
two
in the console. This
looks like text, but when you try to test this with a line such as this one:
myList.selection
"two"
listbox
listbox adds a list to a window. The list can be
created and lled with items
when the window is created, or the items can be added later. To create a list
when the window is created, include it as an array. Here is an example:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
w.show
var
new
Window
"dialog"
var
myList
w.add
"listbox"
myList.add
"item"
"one"
myList.add
"item"
"two"
myList.add
"item"
"three"
w.show
Select an item in the list by clicking it. By default, you can select just one item in
a listbox. To enable
multiple selection, include a creation property:
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"owo"
"three"
multiselect
w.show
With
multiselection enabled, you select items in the usual way: Ctrl/Cmd+click
adds individual items to a selection; Shift+click adds ranges.
var
new
Window
"dialog"
var
myList
w.add
"listbox"
, undefined,
"one"
"two"
"three"
multiselect
myList.selection
w.show
In the screenshot you see white space after the highlight in the rst item, and
there looks to be an empty line at the foot of the the list. These spaces are
reserved by ScriptUI for placing scrollbars if necessary; see the screenshots of
later examples.
In a multiselect list, to select two or more items, write the indexes of the items
as an array:
In InDesign CS6 on
Windows 10 you have to place the
listbox in
a group or a panel, as follows:
var
new
Window
"dialog"
var
gr
w.add
"group"
var
myList
gr.add
"listbox"
, undefined,
"one"
"two"
"three"
w.show
Again, this is CS6 on Windows 10 only. This was noted by Werner
Perplies on
HilfDirSelbst
Make multiple groups act as one group
The scope of
radiobuttons is their container, usually a group or a panel. This
means that all radiobuttons are either laid out as a column or as a row. To
achieve a more exible layout, you can create two groups, say, group A and
group B, add radiobuttons to them, and add an event listener to each group so
that if you click a button in A, all buttons in B are unmarked and the other way
around.
The following script adds two panels to a window, and adds ve radio buttons
to each panel. The event listeners respond to mouse clicks. If you click
var
new
Window
"dialog"
w.orientation
"row"
var
w.add
for
var
"radiobutton"
, undefined,
"Rb "
var
w.add
for
var
"radiobutton"
, undefined,
"Rb "
panel1.children
0].value
panel1.addEventListener
"click"
function
for
var
panel2.children.length

panel2.children
i].value
ddEventListener
"click"
function
for
var
panel1.children.length

panel1.children
i].value
w.show
You could combine the two panels in a group and dene just one event listener
for that group, but that just complicates the event listener and assumes some
labels. We'll give that example in the section on labels.
From CC, .addEventListener() doesn't work in
AfterEects
Illustrator. See
https://forums.adobe.com/
https://forums.
adobe.com/message/6
var
new
Window
"dialog"
var
radio_group
w.add
radio_group.alignChildren
"left"
radio_group.add
"radiobutton"
, undefined,
"InDesign"
radio_group.add
"radiobutton"
, undefined,
radio_group.add
"radiobutton"
, undefined,
"IDML"
radio_group.add
"radiobutton"
, undefined,
"Text"
w.add
"button"
, undefined,
"OK"

check1.value
var
new
Window
"dialog"
w.alignChildren
"left"
var
radio1
w.add
"radiobutton"
, undefined,
"Prefer white"
var
radio2
w.add
"radiobutton"
, undefined,
"Prefer black and white"
radio1.value
w.show
radio1.value
// radio1 selected
// radio2 selected
Finally, it may be useful to add here that a window, group, or panel can be
populated with buttons in a loop. See "Adding callbacks in loops" on page 92
for an example.
checkbox
Here is an example of a window with some checkboxes. Optionally you can
var
new
Window
"dialog"
var
w.add
"checkbox"
, undefined,
"Prefer white"
var
w.add
"checkbox"
, undefined,
"Prefer black and white"
check1.value
w.show
Here we see another window layout default: within a container, items are
centred horizontally. This can be changed with the
alignChildren
property:
var
new
Window
"dialog"
alignChildren
"left"
var
w.add
"checkbox"
, undefined,
"Prefer white"
var
w.add
"checkbox"
, undefined,
"Prefer black and white"
check1.value
w.show
Note that in CS6 and earlier, the text label is much too close to the checkbox.
var
new
Window
"dialog"
w.alignChildren
"left"
w.add
"checkbox"
, undefined,
"Prefer mixed"
w.add
"checkbox"
, undefined,
" Prefer mixed "
w.add
"checkbox"
, undefined,
"\u00A0Prefer mixed"
w.show
In CS5 and CS6, the
should be added at the beginning of the label;
in CS4, at the end. This is a problem of InDesign and the ESTK on Windows in
checkboxes and radiobuttons only. For InDesign, this problem was xed in CC;
in Photoshop and all CS apps on Macs the problem never existed.
CS6 and earlier
From CC
var
var
icons
File
"icon-a.png"
File
"icon-b.png"

File
"icon-c.png"
File
"icon-d.png"
var
new
Window
"dialog"
w.add
"iconbutton"
, undefined, ScriptUI.newImage
icons.a, icons.b, icons.c, icons.d
w.show
The rst icon in the list (here,
icon.a
) is the default and is shown when the
window is drawn. The third one, (c), becomes visible when you click the button;
the last one, (d), is activated on mouse over. The second button, (b), is displayed
when you disable it with a line such as b.enabled = false.
Using
application icons
A tantalising feature of ScriptUI is its ability to use application icons in its
windows. I say ‘tantalising’ because this feature is hopelessly undocumented:
just one remark in the Tools Guide, no further examples or overviews of the
resource names. This is a shame, because access to system resources means that
you don't have to worry about the presence of icons: they must be there since
the application is there.
Here is an example from Photoshop:
b.enabled = false;
Default
Roll over
made to
toggle; buttons
in the screenshot are toggling toolbuttons:
not pressed,
is. Here is the code:
var
new
Window
"dialog"
w.orientation
"row"
var
File
"/d/test/icon.png"
w.add
"iconbutton"
, undefined, f
w.add
"iconbutton"
, undefined, f,
style
"toolbutton"
var
w.add
"iconbutton"
, undefined, f,
style
"toolbutton"
, toggle
var
w.add
"iconbutton"
, undefined, f,
style
"toolbutton"
, toggle
t2.value
w.show
Examples of toggling toolbuttons in InDesign's interface can be found in
var
File
"/d/test/icon.idrc"
try
var
w.add
"iconbutton"
, undefined, f
catch
var
w.add
"button"
, undefined,
This code tries to create an icon button using "icon.idrc", and if the icon can't be
found, a normal button is added with the text @.
The best way to deal with icons is to embed them in the script. Appendix 1
a b c d
w.add
"iconbutton"
, undefined,
File
myFile
This adds a button which is like a pushbutton with an image instead of text
(button
in the screenshot). Buttons can be added as
toolbuttons too, so that
only the image is shown, not the button itself (button
). Finally, buttons can be
Responding to button presses
The behaviour of buttons other than OK and Cancel must be coded explicitely.
You do this with a so-called
onClick
. Here is an example:
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined,
"Abcdefg"
var
convert_button
w.add
"button"
, undefined,
"Convert to upper case"
w.add
"button"
, undefined,
"OK"
convert_button.
function
e.text
e.text.toUpperCase
w.show
Clicking
Convert to upper case
converts the text in the edit eld to upper
case. This is a simple example, but the functions called by onClick can be of any
complexity. (There are several other types of callback, which we will deal with
later.)
Callbacks such as onClick can be combined with other callbacks in one
statement. The following script displays a small panel that we can use to check
the status of the state of the No break attribute.
for numbers and
measurements, you'll have to write them yourself (see p.74
for an example of a script for a measurement control). But though the edit eld
is text only, ScriptUI provides several tools to make the edittext control more
exible so that you can create your own numerical and measurement controls.
The section on event listeners gives an example of how to increment and
decrement numerical values using the up and down arrow keys. Bob
Stucky's
var
new
Window
"dialog"
w.add
"button"
, undefined,
"OK"
w.add
"button"
, undefined,
"Cancel"
w.show
By
default, an OK button responds to pressing the Enter key, a Cancel button to
the Escape key. But these buttons show this behaviour only when the button's
text is OK or Cancel. The Tools Guide therefore recommends to include the
creation property
name: "ok"
to ensure that OK buttons behave appropriately
in localised versions of InDesign or when you want to use some text for a button
other than OK:
var
new
Window
"dialog"
w.add
"button"
, undefined,
"Yes"
"ok"
w.add
"button"
, undefined,
"No"
"cancel"
w.show
In this example, the Yes button behaves like an OK button and the No button
like a Cancel button. (The
property can also be used for nding buttons
and other controls in windows; see "Finding controls" on page 84 for
examples and discussion.)
To create more than one line of text in a button, use \n as a separator (\r doesn't
work on Windows):
w.add
"button"
, undefined,
example, when asking for a
password. Though you can't read the text, it is
accessible to the script via the control's
text
property.
var
new
Window
'dialog {alignChildren: "fill"}'
w.add
'edittext'
, undefined,
w.add
'edittext'
, undefined,
'Read only'
readonly
w.add
'edittext'
, undefined,
'No echo'
w.show
Example: scrollable alert
You can have a script display text, but InDesign's native
alert()
is a bit limited in
that it's not good at handling large amounts of text. It’s not so dicult, however,
// create an example array
array
for
array.push
String
alert_scroll
"Example"
, array
function
alert_scroll
title, input
// string, string/array
// if input is an array, convert it to a string
instanceof
Array
input.join
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined, input,
, scrolling
// the list should not be taller than the maximum possible height of the window
list.maximumSize.height
w.maximumSize.height
list.minimumSize.width
w.add
"button"
, undefined,
"Close"
"ok"
w.show
This function has one drawback: when you input large amounts of text or a big
array, it takes a while to display it.
Controlling edit elds
Controls of type edittext are the only type of input in ScriptUI. There are no
special controls for
numbers,
var
myText
w.add
"edittext"
0, 0, 150, 70], "    ", {multiline: true, scrolling
Although the control is called
edittext
, its edit possibilities are very limited
var
myText
w.add
"edittext"
var
new
Window
"dialog"
var
w.add
"edittext"
, undefined,
"abcdefghijklmnopqrstuvwxyz"
e.active
w.show
As you can see, the text eld is sized correctly but the text is not tted to the
box. To remedy this, add the line highlighted in green:
new
Window
"dialog"
w.add
"edittext"
, undefined,
"abcdefghijklmnopqrstuvwxyz"
layout.layout
e.active
follow w.layout.
layout()
w.show
In versions older than CS6, adding new
lines in an edittext control is a problem:
1-line controls by default, but multi-line texts are possible when the control is
created using the
creation property:
var
Window(
'dialog'
w.add (
'statictext'
'One\rTwo'
w.show();
var
new
Window
'dialog'
w.add
'statictext {text: "Left", characters: 20, justify: "left"}'
w.add
'statictext {text: "Centre", characters: 20, justify: "center"}'
w.add
'statictext {text: "Right", characters: 20, justify: "right"}'
w.show
The
characters
var
new
Window
"dialog"
"Multiline"
var
myText
w.add
"edittext"
0, 0, 150, 70], "    ", {multiline: true});   myText.text
myText.active
w.show
In the screenshot we've added a few lines. As you can see, we specied the
size of the control in the second argument position ([0, 0, 150, 70]) – these
dimensions are left, top, width, and height. (Note that these coordinates dier
new
Window
'dialog'
w.grp1
w.add
'group'
w.grp1.add
0,0,100,100], 'None'
borderStyle
'none'
w.grp1.add
0,0,100,100], 'Gray'
borderStyle
'gray'
w.grp1.add
0,0,100,100], 'Black', {borderStyle
w.grp1.add
0,0,100,100], 'White'
borderStyle
'white'
w.grp2
w.add
'group'
w.grp2.add
0,0,100,100], 'Etched'
borderStyle
Displaying creation properties
Formatting the window frame
There
new
Window
"dialog"
"Example"
, undefined,
closeButton
w.add
"statictext"
, undefined,
"closebutton: f
alse"
w.show
You can do borderless frames, too:
new
Window
"dialog"
, undefined, undefined,
borderless
w.add
"statictext"
, undefined,
"borderless: t
rue"
w.show
new
Window
"dialog"
, undefined, undefined,
borderless
margins
0,0,0,0];   myPanel
w.add
myPanel.add
"statictext"
, undefined,
"borderless: not quite true"
w.show
You'll notice, naturally, that the frame is not a border on the window but of the
panel.
Panel border styles
Panels are drawn with a black frame rule by default. In
Photoshop and
After
Eects (not in InDesign and
Illustrator) the appearance of the frame rule can be
changed using the creation property
borderStyle
We'll decide that the window is good enough for our purposes, and now we
turn to the question of how to deal with the user's input and how to use that
input in the rest of the script. In this example, two things can happen: the user
clicks OK (which in this script corresponds to pressing Enter) or they can click
Cancel (which is the equivalent of pressing Escape). The window's behaviour is
this: if the user presses OK, the line
myWindow
.show(
myWindow.show
var
myName
myText.text
exit
In this case we needn't check for Escape because there are just two options,
namely, OK and Cancel. So if the user didn't press OK they must have pressed
var
myName
myInput
// rest of the script
function
myInput
var
myWindow
new
Window
"dialog"
"Form"
var
myInputGroup
myWindow.add
"group"

myInputGroup.add
"statictext"
, undefined,

var
myText
myInputGroup.add
"edittext"
, undefined,
"John"

myText.characters

myText.active
var
myButtonGroup
myWindow.add
"group"

myButtonGroup.alignment
"right"

myButtonGroup.add
"button"
, undefined,
"OK"

myButtonGroup.add
"button"
, undefined,
"Cancel"
myWindow.show
var
myWindow
new
Window
"dialog"
"Form"
var
myInputGroup
myWindow.add
"group"
myInputGroup.add
"statictext"
, undefined,
var
myText
myInputGroup.add
"edittext"
, undefined,
"John"

myText.characters

myText.active
var
myButtonGroup
myWindow.add
"group"
myButtonGroup.
alignment
"right"
myButtonGroup.add
"button"
, undefined,
"OK"
myButtonGroup.add
"button"
, undefined,
"Cancel"
myWindow.show
We dened two groups,
myInputGroup
myButtonGroup
. Note that we
var
myWindow
new
Window
"dialog"
"Form"
myWindow.orientation
"row"
var
myInputGroup
myWindow.add
"group"
myInputGroup.add
"statictext"
, undefined,
var
myText
myInputGroup.add
"edittext"
, undefined,
"John"
myText.characters
myText.active
var
myButtonGroup
myWindow.add
"group"
myButtonGroup.orientation
"column"
myButtonGroup.add
"button"
, undefined,
"OK"
myButtonGroup.add
"button"
, undefined,
"Cancel"
myWindow.show
A nal tweak might be to align the two groups vertically. To do this, add this line
to the script; just before or after the second line makes sense:
myWindow.
alignChildren
"top"
The script's window is now displayed as shown on the right.
var
myWindow
new
Window
"dialog"
"Form"
myWindow.orientation
"row"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
, undefined,
"John"
myText.characters
myWindow.onShow
function
myText.active
myWindow.show
Now we want to add some buttons, in this case the usual OK and Cancel
buttons. We do this using the
button
control:
var
myWindow
new
Window
"dialog"
"Form"
myWindow.orientation
"row"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
, undefined,
"John"
myText.characters
myText.active
myWindow.add
"button"
, undefined,
"OK"
myWindow.add
"button"
, undefined,
"Cancel"
myWindow.show
But this doesn't look right, we want the buttons laid out in a dierent way.
Groups and panels
_index_active@ 5290
_idTOCAnchor-92
_ix_dest_orientation #panel 6
_ix_dest_orientation #group 6
var
myWindow
new
Window
"dialog"
"Form"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
myWindow.show
Note rst that we added a title to the
window ('Form'). (Titles are centred on
the Mac.) Also note that the edit eld appears below its title Name, which is not
what we want. A
window's default orientation is
column
. To change that to
row
we need to include a statement to that eect:
var
myWindow
new
Window
"dialog"
"Form"
myWindow.
orientation
"row"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
myWindow.show
var
myWindow
new
Window
"dialog"
"Form"
myWindow.orientation
"row"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
, undefined,
"John"
myText.
characters
myWindow.show
var
myWindow
new
Window
"dialog"
"Form"
myWindow.orientation
"row"
myWindow.add
"statictext"
, undefined,
var
myText
myWindow.add
"edittext"
, undefined,
"John"
myText.characters
myText.
active
myWindow.show
Note
: To make
active
For control titles, see also p. 78
Dierences accross operating systems
var
myMessage
myWindow.add
"statictext"
, undefined,
"Hello, world!"
var
myMessage
myWindow.add
"statictext {text: 'Hello, world!'}"
using a so-called resource string (resource strings are dealt with more
extensively in the section "Resource string" on page 115). In what follows I'll
var
createWindow
win.show
function
createWindow
var
new
Window
function
function
createWindow
var
new
Window
function
var
new
Window
Hello world
Inevitably, the simplest window is one that prints a message on the screen. Here
is an example that displays a simple ScriptUI window, showing the bare basics
of a ScriptUI window:
var
myWindow
new
Window
"dialog"
var
myMessage
myWindow.add
"statictext"
myMessage.text
"Hello, world!"
myWindow.show
The rst line denes a new window of type
; the second line adds
control
to the window, here a
statictext
In fact, scriptUI has a third window type,
window
Measurement control
Simulating keypresses
Adding shortcut keys to controls
Control titles
Adding and removing controls dynamically
......................
Labelling controls
Finding windows
Finding controls
Closing windows
Fonts
Colours
Callbacks
Adding callbacks in loops
Event handlers
Monitoring the mouse
Contents
Hello world
Types of window
Beginning ScriptUI
ScriptUI is a module in the Adobe CS/CC family of applications (starting in CS2
in Photoshop, in CS3 for InDesign and other CS and CC applications) with which
dialogs can be added to scripts written in JavaScript. The module is included in
each version of the ExtendScript Toolkit, and dialogs written in it can be used

Приложенные файлы

  • pdf 10969530
    Размер файла: 2 MB Загрузок: 2

Добавить комментарий