Your prescription for increased productivity and profitability
Working from a center point proves useful for a number of reasons when it comes to automation. In our previous blog we went so far as to use a random number generator to place an object at random locations within a page. With this post we will step back and use the concept of “drawing” from center to create objects other than circles and rectangles. How about a triangle? Perhaps one to be used as a button for navigating an interactive document or states within a multi-state object. You may want to review our previous blog post as we will be borrowing some concepts and handlers from there. Our demonstration script will require knowing some basics of paths in InDesign.
A path can be open or closed and is defined by x/y geometric points. Points on a path can be one of four types: corner, line type, smooth, or symmetrical. A list of all of the points within a path is described by the entire path property. For a path that consists of points that are either line type or corner, the entire path will be a list of x-y coordinates. To describe our triangle its path will need three points, possibly equidistant from a center point. Notice how the entire path and the geometric bounds for the triangle are defined in the following.
(*Draw Triangle from Center Assumes user has a document open in Adobe InDesign*) set cx to 200 set cy to 100 set r to 30 set polypoints to {{cx, cy - r}, {cx + r, cy}, {cx, cy + r}} set gBounds to {cy - r, cx - r, cy + r, cx + r} tell application "Adobe InDesign CC 2019" set measurement unit of script preferences to points set myPage to page 1 of active spread of active window tell myPage set polyRef to make polygon with properties ¬ {geometric bounds:gBounds, stroke weight:2, fill color:"Black", stroke color:"Black"} end tell tell path 1 of polyRef set entire path to polypoints set path type to closed path end tell end tell
The result of this routine is a triangle that “points” to the right. To point the triangle to the left, the x coordinate value for the second point needs to be subtracted from center. We can do this by introducing a second variable (f). See how it is used to define the points for two triangles, one pointing left and one pointing right.
(*Draws 2 Triangles from Center Assumes user has a document open in Adobe InDesign*) set cx to 200 set cy to 100 set r to 30 tell application "Adobe InDesign CC 2019" set measurement unit of script preferences to points set myPage to page 1 of active spread of active window set f to 1 --used to alter x parameter of a point my makeTriangle (myPage, cx, cy, r, f) set f to -1 my makeTriangle(myPage, cx, cy, r, f) end tell on makeTriangle(pageRef, cx, cy, r, f) set gBounds to {cy - r, cx - r, cy + r, cx + r} set polyPoints to {{cx, cy - r}, {cx + f * r, cy}, {cx, cy + r}} tell application "Adobe InDesign CC 2019" tell pageRef set polyRef to make polygon with properties ¬ {geometric bounds:gBounds, stroke weight:2, fill color:"Black", stroke color:"Black"} end tell tell path 1 of polyRef set entire path to polyPoints set path type to closed path end tell end tell end makeTriangle
When you run this script, what you end up with looks like a square that has been rotated.
What we need to add to the script is a value that defines a distance for the space between the triangles coordinates (from center to center). Create a variable d that will represent this value. Add to the top of the script
set d to 20
Change the calls to the makeTriangle handler to pass this value with the others in the above script.
set f to 1 set triangle1 to my makeTriangle (myPage, cx, cy, r, f, d) set f to -1 set triangle2 to my makeTriangle (myPage, cx, cy, r, f, d)
With this we can change the makeTriangle handler to read as follows:
on makeTriangle(pageRef, cx, cy, r, f, d) set cx to cx + (d * f) set cy to cy set gBounds to {cy - r, cx - r, cy + r, cx + r} set polyPoints to {{cx, cy - (r - d)}, {cx + f * r, cy}, {cx, cy + (r - d)}} tell application "Adobe InDesign CC 2019" tell pageRef set polyRef to make polygon with properties ¬ {geometric bounds:gBounds, stroke weight:2, fill color:"Black", stroke color:"Black"} end tell tell path 1 of polyRef set entire path to polyPoints set path type to closed path end tell end tell return polyRef end makeTriangle
For our demonstration script we will use triangular buttons to navigate a multi stage object.
For this you will need a folder of some images of the same size and resolution and an InDesign document open. To get a list of the files in the folder we can use the following:
set thePrompt to "Choose folder of files for multi state object" set imagePath to (choose folder with prompt thePrompt) as string set fileList to list folder imagePath without invisibles
We can then use Image Events to determine the size we will need for our multi state object. Let’s write this as a handler.
Add to the three lines above:
set {wid, hgt} to getImageDimensions(imagePath, item 1 of fileList) (*Handler returns dimensions of sample image*) on getImageDimensions(imagePath, sampleItem) set imageRef to imagePath & sampleItem tell application "Image Events" set fileRef to open imageRef set theDim to dimensions of fileRef set res to resolution of fileRef close fileRef end tell copy theDim to {wid, hgt} return {wid, hgt} end getImageDimensions
Using these dimensions a multi state object can be created. The top of the script can now read as follows:
set thePrompt to "Choose folder of files for multi state object" set imagePath to (choose folder with prompt thePrompt) as string set fileList to list folder imagePath without invisibles set sampleItem to item 1 of fileList set {wid, hgt} to getImageDimensions(imagePath, sampleItem) tell application "Adobe InDesign CC 2019" set measurement unit of script preferences to points set pageRef to page 1 of active spread of active window copy bounds of pageRef to {py0, px0, py1, px1} set cx to round (px1 / 2) set cy to round (py1 / 2) set gBounds to {cy - (hgt / 2), cx - (wid / 2), (cy + hgt / 2), (cx + wid / 2)} set aliasRef to (imagePath & item 1 of fileList) as alias tell pageRef set mRef to make multi state object with properties {name:"MSO", geometric bounds:gBounds} end tell end tell
Make sure you have the getImageDimensions handler at the bottom of the script and test. An empty rectangle frame will indicate the object created.
When a multi state object is added to a page, it has two states by default. The script will need to add states so the total number of states will be the same as the number of images.
Add the following to the top of the script just before the last end tell.
set numItems to length of fileList tell mRef repeat (numItems - 2) times make state end repeat end tell
Lastly, the script needs to loop through the list of images and place them into the multi state object. Add the following after the lines added above:
repeat with i from 1 to length of fileList set fileName to item i of fileList tell state i of mRef set rectRef to make rectangle with properties {geometric bounds:gBounds, name:("State" & i)} end tell tell rectRef to place ((imagePath & fileName) as alias) end repeat
Remove the multi state object created in the test above from the document and test the script.
The script will work as anticipated if the images for the document were saved with resolutions of 72 dpi. If not, you will need to make adjustments to the getImageDimensions handler so the effective sizes returned will be at 72 dpi.
To allow the user to navigate through the multi state object, the script will now create buttons. For this the following variables will need to be added to the top of the script.
set r to 8 -- the width of the triangle in points set d to 20 --the distance between the triangles set oset to 12 --the distance below the bottom of the multi state object and the triangles
The script will add the buttons using two handlers:
1. addButtons – Calls a handler that creates the button
2. makeButton – Creates a triangular button
Start by adding a call to a handler named addButtons. Add this after the last end tell at the top of the script:
set cy to cy + hgt/2 + oset + r/2 addButtons (pageRef, "MSO", cx, cy, r, d)
The addButtons handler calls the handler that creates a button and then sets up the behavior for the individual buttons. Add the following to the bottom of the script:
(*Adds two buttons by calling handler that creates button, adds behavior to each button*) on addButtons (pageRef, msoName, cx, cy, r, d) tell application "Adobe InDesign CC 2019" set mRef to multi state object msoName of document 1 tell pageRef set f to -1 set btn1 to my makeButton(pageRef, cx, cy, r, f, d) tell btn1 make goto previous state behavior with properties ¬ {associated multi state object:mRef, enable behavior:true, loops to next or previous:true, behavior event:mouse down} end tell set f to 1 set btn2 to my makeButton(pageRef, cx, cy, r, f, d) tell btn2 make goto next state behavior with properties ¬ {associated multi state object:mRef, enable behavior:true, loops to next or previous:true, behavior event:mouse down} end tell end tell end tell end addButtons (*Creates triangular shaped button using center coordinates*) on makeButton(pageRef, cx, cy, r, f, d) set cx to cx + (d * f) set cy to cy set gBounds to {cy - r, cx - r, cy + r, cx + r} set polyPoints to {{cx - (r * f), cy - r}, {cx + f * r, cy}, {cx - (r * f), cy + r}} tell application "Adobe InDesign CC 2019" set btnProps to {stroke weight:2, fill color:"Black", stroke color:"Black"} tell pageRef set btnRef to make button with properties {geometric bounds:gBounds} end tell tell state 1 of btnRef set myPoly to make polygon with properties btnProps set entire path of path 1 of myPoly to polyPoints end tell end tell return btnRef end makeButton
…Our multi state object
Clear the multi state object from the document and test the script. View the interactivity of the completed project using the EPUB Interactivity Preview (Window > Interactive > EPUB Interactivity Preview).
Yes, there is a fair amount of code involved in this script. But it is so useful. Think of the steps required to make a multi state object manually. It can be a little tedious.
To complete the script, add a trap for errors (user cancels out of choose file dialog, or other.
Additionally, suppose you want your buttons to be placed to the left and right of the multi state object. Just a couple of variable values need to be changed in the script to make this happen. Can you spot them?
Hint: The cy value will be the original value (y coordinate for the multi state object center point). The d value will be one-half of the width of the multi state object plus an offset value.
Try it.
For a real challenge add a dialog box to have the user define the values for the project parameters:
You could even provide widgets for color, fill, and stroke, or a dropdown to choose an object style. Be creative.
Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.