With this blog post we are wrapping up our journey into the automation of a multi-state-object slideshow with two stylistic options.

The approach for the coding took a little different turn in that the InDesign document was created based on the size and resolution of the images. This provided the opportunity to introduce a handy AppleScript application, Image Events, which provides a quick and effective way to get information about an image file.

This is done in a handler named getImageFilesWithInfo which has the user choose the folder for the files to be used in the slideshow. The handler returns the path to the folder chosen by the user (string), a list of the file names, along with the size and resolution of a representative file.

For review, the script starts by defining values for variables to be used within the script. These are needed to create a custom dialog and handle the user’s response:

set colorList to getColorList() --returns a list of default colors which will be available for the document
set buttonColor to {"Blue", "Gray", "Green", "Red", "Black"}
set btnNumbers to {143, 145, 147, 149, 151}
set dlgName to "Slideshow Style"

This is followed by a call to the getImageFilesWithInfo handler.

--Get path to files, file list, dimension and resolution for sample file
set thePrompt to "Choose folder of files for slideshow"
set theResult to getImageFilesWithInfo(thePrompt)
copy theResult to {folderPath, fileList, theDim, theRes}


Because the resolution of the images can be different than the screen resolution, the script, the script calculates the width and height for the document to be created based on resolution.

--Get path to files, file list, dimension and resolution for sample file
set thePrompt to "Choose folder of files for slideshow"
set theResult to getImageFilesWithInfo(thePrompt)
copy theResult to {folderPath, fileList, theDim, theRes}

Custom Dialog

The script then calls a handler to have the user choose which of two choices to use for the slideshow presentation: (1) placing the buttons to the sides and over the image, or (2) in a margin area below the image.

--get style information from user - define values needed for the dialog and call handlers
set dlgResult to doDialog(dlgName, true, colorList, buttonColor)

Create Dialog

Depending on the result from the dialog, the script then creates the document making adjustments for the bottom margin area should the second option be chosen. The geometric bounds for the multi-state object is also defined at this point.

if item 1 of dlgResult is "Style2" then
   set bottomMargin to 60
   set bottomMargin to 0
end if
set pgHgt to (pgHgt + bottomMargin)
set marginList to {0, 0, bottomMargin, 0}
set gBounds to {0, 0, pgHgt - bottomMargin, pgWid}
--create the document
set docRef to createDocument(pgWid, pgHgt, marginList)

Multi-State Object

The multi-state object is then created with a call to the createMultistate handler (createMSO).

--Create the Multi-State Object
set MSObject to createMSO(docRef, gBounds, folderPath, fileList)


So far, so good. It gets a little more involved when it comes to adding the buttons. Depending on the slideshow style selected by the user, the position for the buttons is calculated, and the buttons placed or created. The calculation is done in a handler named getPlaceInfo.

(*Calculates path and boundsd for buttons based on value of variable pos*)
on getPlaceInfo(pos, pgWid, pgHgt, btnWid, btnHgt, margin)
   if pos is "sides" then
	set x0 to margin
	set b2x0 to pgWid - (margin + btnWid)
	set cy to round (pgHgt / 2)
	set y0 to cy - (btnHgt / 2)
	set y1 to y0 + btnHgt
	set x1 to x0 + btnWid
	set gBounds1 to {y0, x0, y1, x1}
	set gBounds2 to {y0, b2x0, y1, b2x0 + btnWid}
	set path1 to {{x1, y0}, {x1 - btnWid, cy}, {x1, y1}}
	set path2 to {{b2x0, y0}, {b2x0 + btnWid, cy}, {b2x0, y1}}
	return {gBounds1, path1, gBounds2, path2}
   else if pos = "bottom" then
	set cx to round (pgWid / 2)
	set cy to (pgHgt - (margin + (btnHgt)))
	set placePt1 to {(cx - (margin + (btnWid / 2))), cy}
	set placePt2 to {(cx + margin), cy}
	return {placePt1, placePt2}
   end if
end getPlaceInfo

Button Setup

If the user selected the first style (Style1), the getPlaceInfo handler will return geometric bounds and path points for each button {gBounds1, path1, gBounds2, path2}.

These values are passed to the handler that actually creates the button (strokeOnlyButton handler). See below.

The following is added to the code above to get the information needed for placing the buttons and calling the handlers that will create or place the buttons:

if item 1 of dlgResult is "Style1" then
   set clrIndex to item 2 of dlgResult
   set btnColor to item clrIndex of colorList
   --params: btn width, btn height, margin from sides
   --returns  return {gBounds1, path1, gBounds2, path2}   
   set placeInfo to getPlaceInfo("sides", pgWid, pgHgt, 15, 40, 30)
   copy placeInfo to {gBounds1, path1, gBounds2, path2}
   set btn1 to strokeOnlyButton("LeftButton", gBounds1, path1, btnColor, false)
   set btn2 to strokeOnlyButton("RightButton", gBounds2, path2,btnColor, false)
else if item 1 of dlgResult is "Style2" then
   set btnNumber to item 2 of dlgResult
   set btnNum1 to item btnNumber of btnNumbers
   set btnNum2 to btnNum1 + 1
   --returns {placePt1, placePt2} {{366.5, 618}, {424, 618}}
   --params: btn Width, btn Height, margin between
   set placeInfo to getPlaceInfo("bottom", pgWid, pgHgt, 19, 18, 24)
   --make sure library is open
   set libRef to getButtonLibrary()
   --place buttons as library assets; page number, library reference, button name, place point, number of asset
   set btn1 to placeAsset(1, libRef, "LeftButton", item 1 of placeInfo, btnNum1)
   set btn2 to placeAsset(1, libRef, "RightButton", item 2 of placeInfo, btnNum2)
end if

The Stroke Only Button

(*The strokeOnlyButton handler*)
on strokeOnlyButton(btnName, btnBounds, pathPoints, btnColor, closePath)
   tell application "Adobe InDesign CC 2018"
	if closePath is true then
	   set myPathType to closed path
	   set myPathType to open path
	end if
	set docRef to document 1
	tell docRef
	   if not (exists layer "Button Layer") then
		set layerRef to make layer with properties {name:"Button Layer"}
		set layerRef to layer "Button Layer"
	   end if
	   set btnProps to {stroke weight:3}
	   tell page 1
		set theBtn to make button with properties {name:btnName, item layer:layerRef, geometric bounds:btnBounds, fill color:"None"}
		tell state 1 of theBtn
			set myArrow to make polygon with properties btnProps
			set fill color of myArrow to "None"
			set entire path of path 1 of myArrow to pathPoints
			set stroke color of myArrow to btnColor
			set path type of path 1 of myArrow to myPathType
		end tell
	   end tell
        end tell
    end tell
    return theBtn
end strokeOnlyButton

Library Button

Using the Button from InDesign’s Button Library is not as straightforward as you might imagine. First the script needs to ascertain if the library is open, and open it if not. After working with several options, the following handler seemed to be the most reliable:

--make sure button library is open
on getButtonLibrary()
   tell application "Adobe InDesign CC 2018"
	set libPanel to library panel "Sample Buttons And Forms"
	set libRef to associated library of libPanel
      on error
	set appPath to file path as string
	set libPath to appPath & "Presets:Button Library:ButtonLibrary.indl"
	set libAlias to libPath as alias
	set libRef to open libAlias
      end try
      return libRef
   end tell
end getButtonLibrary

Placing assets from a library is something that might be needed in a number of projects, so the handler was written with that in mind:

(*Places asset to page defined by its index, using a reference to the library, 
the asset name, the place point (x,y), and the button number*)
on placeAsset(pageNumber, libraryRef, assetName, placePt, assetNumber)
   tell application "Adobe InDesign CC 2018"
      set pageRef to page pageNumber of document 1
      set assetRef to asset ("" & assetNumber) of libraryRef
      set placedObj to place asset assetRef on document 1
      move placedObj to pageRef
      move placedObj to placePt
      set theAsset to item 1 of placedObj
      set name of theAsset to assetName
   end tell
   return theAsset
end placeAsset

Notice that with assets, the asset is placed on the document then moved to the page, and finally to the place point on the page.

Button Behaviors

All that is left for the script to do is to wire the buttons up to the multi-state-object. This involves adding behaviors to the buttons. We could put the code in its own handler, but it ca be placed at the bottom of the top portion of our script.

--add Button behaviors
tell application "Adobe InDesign CC 2018"
   tell btn1
      make goto previous state behavior with properties {associated multi state object:MSObject, behavior event:mouse down, enable behavior:true, loops to next or previous:true}
   end tell
   tell btn2
      make goto next state behavior with properties {associated multi state object:MSObject, behavior event:mouse down, enable behavior:true, loops to next or previous:true}
   end tell
end tell


The handlers called from the code above are listed below:

  • getButtonLibrary – make sure button library is open
  • placeAsset – requires page number, reference to library, asset name, place point and button number
  • strokeOnlyButton – creates the arrow buttons requiring the naame for the button, it bounds, the path points, and aa boolean to incidate if the path will be closed or open getImageFilesWithInfo – Has user choose the folder of files. Returns the folder path, the names of the files, as well as size and resolution of image sampled using Image Events
  • createDocument – creates single page document for web intent.
  • createMSO – creates the multi state object adding states needed for image;, creates containers and places images
  • getPlaceInfo – calculates geometric bounds and paths or place points for the buttons
  • doDialog – creates a simple user dialog with enabling groups
  • getColorList – returns list of default colors available for the document to populate dropdown for custom dialog

For handlers not listed above, you will find these handlers in our posts for January 16, 24, and 30. You can download the entire script from the Feature page of our website.


Notice, with one exception, all of the code directed to the application was placed inside handlers. This not only makes code reusable, but makes it possible to test each portion as you go. With each piece tested, the script should be fairly bullet proof, but we do need to add a try/on error trap in the event that the user decides to cancel out of the choose folder or the custom dialog. We will leave that up to the reader.

For the acid test, run the script, choose one of the styles from the dialog and see how fast the document and its content is created. Next open the EPUB Interactivity Preview window and click the run button. The slideshow should load almost immediately. Click the buttons and verify the slideshow works as anticipated.

…Previewing the slideshow


You can share your slideshow with the world using InDesign’s Publish to Web. This gives you several options for sharing your slideshow. One is to copy the url providerd when you Publish to Web and share it with your audience.

For example, you can view the sample sllidesow created with the script by clicking on the following link Click Here.


Scripts provided are for demonstration and educational purposes. No representation is made as to their completeness. Users are advised to use the code at their own risk.