I have a script that searches for missing images in an InDesign document and updates each image if it is found. If it finds more than 1 image available for a missing image, it displays a dialog with the paths to each image so the user can choose which image they want to use.
Below is a code sample with the part that displays the dialog. Instead of displaying a dialog with several image paths that the user can choose from, I would like to display a dialog with thumbnails of each image with the image’s name beneath them. Is there a way to do this using Applescript Objective C or InDesign custom dialogs? If so, any help on how to do that would be greatly appreciated!
set example_image_number to "*317871*"
set example_image_name to "317871.jpg"
set example_images_folder to POSIX path of "/Volumes/NAS/Advertising Department/2_IMAGES - HIGH RES FOR PRINT/1_4c IMAGES/"
--Doing a search for the image number
set image_search to paragraphs of (do shell script "find " & quoted form of (POSIX path of example_images_folder) & " -name '" & example_image_number & "' -type f") -->searching
--Displaying a list of found images to choose from if more than 1 image is found for that number
if length of image_search is greater than 1 then
tell application "Adobe InDesign CC 2018"
activate
set prompt_name to "Please select the correct image to replace missing image " & example_image_name & " with:"
set my_choice to (choose from list image_search with prompt prompt_name) as string
end tell
end if
Yes it is possible, I’m showing complex dialogs, progress indicators, modal windows and other things using only AppleScriptObjC (without any NIB file). Here is how you create an window on the Fly properly, don’t worry about the script object because it will be released after the window closes. Which means it’s like an “stay-open application”.
use AppleScript version "2.5"
use framework "Foundation"
property NSWindowController : class "NSWindowController"
property NSWindow : class "NSWindow"
property windowController : missing value
set theWindow to createWindowWithRect(0, 0, 500, 500)
set windowController to createWindowController(theWindow)
windowController's |window|()'s |center|()
my performSelectorOnMainThread:"showWindowSelector:" withObject:me waitUntilDone:true
return
on createWindowWithRect(xMin, yMin, xLen, yLen)
set windowSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
set aWindow to NSWindow's alloc()'s initWithContentRect:windowSize styleMask:7 backing:2 defer:yes
return aWindow
end createWindowWithRect
on createWindowController(aWindow)
set wController to NSWindowController's alloc()'s initWithWindow:aWindow
end createWindowController
on showWindowSelector:sender
windowController's |window|()'s makeKeyAndOrderFront:me
end showWindowSelector:
This is a good skeleton to start with and you can add subviews to theWindow to you liking.
When I look up how to add an image to a subview, I found the following code which does not play well with the Script Editor. (It keeps telling me UIImage is undefined).
Here’s something else I tried, which gives no errors but also doesn’t add the image or subview.
use AppleScript version "2.4"
use framework "Foundation"
property NSWindowController : class "NSWindowController"
property NSWindow : class "NSWindow"
property windowController : "Cooperate"
set theWindow to createWindowWithRect(0, 0, 500, 500)
set windowController to createWindowController(theWindow)
windowController's |window|()'s |center|()
my performSelectorOnMainThread:"showWindowSelector:" withObject:me waitUntilDone:true
return
on createWindowWithRect(xMin, yMin, xLen, yLen)
set windowSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
set aWindow to NSWindow's alloc()'s initWithContentRect:windowSize styleMask:7 backing:2 defer:yes
return aWindow
end createWindowWithRect
on createWindowController(aWindow)
set wController to NSWindowController's alloc()'s initWithWindow:aWindow
end createWindowController
on showWindowSelector:sender
windowController's |window|()'s makeKeyAndOrderFront:me
set mySubview to windowController's |window|()'s addSubview:me
set myImage to mySubview()'s initWithImage:"/Volumes/NAS/Advertising Department/2_IMAGES - HIGH RES FOR PRINT/1_4c IMAGES/AG1113214(2_18)_s_4c.tif"
end showWindowSelector:
I’m just studying your script to try and understand how it works.
Shouldn’t it also use the “AppKit” framework?
All the methods seem to date from Mac OS 10.0 or 10.2, so maybe AppleScript version “2.4” would be OK.
The NSWindowController is only used here to get references to the window — to which the script has a reference already. Presumably the controller would have other uses if the skeleton were expanded.
Is there any essential difference between this:
on showWindowSelector:sender
windowController's |window|()'s makeKeyAndOrderFront:sender -- me
end showWindowSelector:
… and this?:
on showWindowSelector:sender
windowController's showWindow:sender
end showWindowSelector:
It’s indeed better to write it explicitly, I agree. The reason I don’t is that every application that’s capable of running AppleScriptObjC code has AppKit already loaded. In order for an process to become an application it has to load in instance of NSApplication which is part of the AppKit framework.
The context was more that’s it’s better to use the latest version of AppleScript rather than it won’t work in older AppleScript versions.
That’s correct, this specific example could do without an window controller because it doesn’t require specific needs.
In this case not really because there is only one window and that windows becomes inherently key and front most. As with my previous answer, in this specific example showWindow: works the same but when you expand the script it can behave differently. When expanding the script working with multiple windows, sheets and or panels or change the default behavior of this window, showWindow: can behave differently from makeKeyAndOrderFront:.
UIImage is for iOS, not macOS. You need NSImage. This should give you something to go on:
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
property NSWindow : a reference to current application's NSWindow
property NSImage : a reference to current application's NSImage
property NSImageView : a reference to current application's NSImageView
property NSWindowStyleMaskTitled : a reference to 1
property NSWindowStyleMaskClosable : a reference to 2
set theWindow to createWindowWithRect(0, 0, 500, 500)
my performSelectorOnMainThread:"showTheWindow:" withObject:theWindow waitUntilDone:true
on createWindowWithRect(xMin, yMin, xLen, yLen)
set windowSize to {{xMin, yMin}, {xLen, yLen}}
set winStyle to NSWindowStyleMaskTitled + NSWindowStyleMaskClosable
set aWindow to NSWindow's alloc()'s initWithContentRect:windowSize styleMask:winStyle backing:2 defer:yes
return aWindow
end createWindowWithRect
on showTheWindow:theWindow
set theImage to NSImage's alloc()'s initWithContentsOfFile:"/users/shane/Desktop/IMG_0194.jpg"
set theImageView to NSImageView's alloc()'s initWithFrame:{{50, 50}, {400, 400}}
theWindow's contentView()'s addSubview:theImageView
theImageView's setImage:theImage
theWindow's makeKeyAndOrderFront:me
end showTheWindow:
There’s more to it, though. The use framework statement also tells AppleScript to load the framework’s .bridgesupport file, which in turn is required for various bits of terminology, as well as some methods. I actually asked one of the engineers about it, and he was quite emphatic that it should be included.
Didn’t knew that. Always assumed that the very slow startup of AppleScriptObjC was mostly caused by loading bridge supports files of already loaded frameworks (or application frameworks).
Sweet! I have it displaying a window with four images from an AppleScript list now. I need to do some more research on adding text and buttons and passing the chosen button back to AppleScript. How did you learn Objective C?
-------------------------------------------------------------------------------------------------------------
--ADDING THE MISSING IMAGES TO A LIST
-------------------------------------------------------------------------------------------------------------
--Adding the images to the list
tell application "Finder"
set image_option1 to POSIX path of "Volumes:NAS:Advertising Department:2_IMAGES - HIGH RES FOR PRINT:1_4c IMAGES:CLK - High Res:CLK_ BY BLAIN NUMBERS - High Res:CLK_0 - CLK_5 - High Res:CLK1029172_VFJeanswear(5_18)A_s_4c.tif" as string
set image_option2 to POSIX path of "Volumes:NAS:Advertising Department:2_IMAGES - HIGH RES FOR PRINT:1_4c IMAGES:CLK - High Res:CLK_ BY BLAIN NUMBERS - High Res:CLK_0 - CLK_5 - High Res:CLK1029172_VFJeanswear(5_18)B_s_4c.tif" as string
set image_option3 to POSIX path of "Volumes:NAS:Advertising Department:2_IMAGES - HIGH RES FOR PRINT:1_4c IMAGES:CLK - High Res:CLK_ BY BLAIN NUMBERS - High Res:CLK_0 - CLK_5 - High Res:CLK1029172_VFJeanswear(5_18)C_s_4c.tif" as string
set image_option4 to POSIX path of "Volumes:NAS:Advertising Department:2_IMAGES - HIGH RES FOR PRINT:1_4c IMAGES:CLK - High Res:CLK_ BY BLAIN NUMBERS - High Res:CLK_0 - CLK_5 - High Res:CLK1029172_VFJeanswear(5_18)D_s_4c.tif" as string
set image_list to {image_option1, image_option2, image_option3, image_option4}
--Getting the number of items in the list
set image_count to count image_list
--Figuring out the height of the display window based on the number of images in the list
if image_count is less than or equal to 4 then
set image_rows to 1
else
set image_rows to 2
end if
set screen_height to (400 * image_rows) as number
end tell
-------------------------------------------------------------------------------------------------------------
--CREATING THE UI WINDOW
-------------------------------------------------------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
property NSWindow : a reference to current application's NSWindow
property NSImage : a reference to current application's NSImage
property NSImageView : a reference to current application's NSImageView
property NSWindowStyleMaskTitled : a reference to 1
property NSWindowStyleMaskClosable : a reference to 2
set theWindow to createWindowWithRect(0, 0, 1000, screen_height)
my performSelectorOnMainThread:"showTheWindow:" withObject:theWindow waitUntilDone:true
--Creating the window
on createWindowWithRect(xMin, yMin, xLen, yLen)
set windowSize to {{xMin, yMin}, {xLen, yLen}}
set winStyle to NSWindowStyleMaskTitled + NSWindowStyleMaskClosable
set aWindow to NSWindow's alloc()'s initWithContentRect:windowSize styleMask:winStyle backing:2 defer:yes
return aWindow
end createWindowWithRect
--**********--**********--**********--**********--**********--
--> add the heading "MULTIPLE IMAGE(S) FOUND. Which image would you like to use?" to the UI
--**********--**********--**********--**********--**********--
--Adding the images to the UI Window
set x1 to 200
repeat with image_option in image_list
tell application "Finder" to set image_name to name of (POSIX file (image_option as string) as alias) -->getting the image name for the label
log image_name
set theImage to (NSImage's alloc()'s initWithContentsOfFile:image_option)
set theImageView to (NSImageView's alloc()'s initWithFrame:{{25, 50}, {x1, 300}})
(theWindow's contentView()'s addSubview:theImageView)
(theImageView's setImage:theImage)
--**********--**********--**********--**********--**********--
--> add image name beneath the image as a label to the UI
--**********--**********--**********--**********--**********--
--**********--**********--**********--**********--**********--
--> add buttons to the UI for the user to choose which image they want to use
--**********--**********--**********--**********--**********--
set x1 to (x1 + 450)
end repeat
--Showing the window
on showTheWindow:theWindow
(theWindow's makeKeyAndOrderFront:me)
end showTheWindow:
--**********--**********--**********--**********--**********--
--> Pass the selected image back to AppleScript as a variable
--**********--**********--**********--**********--**********--
You can define the handler that’s need to be called when an button is clicked by using setAction: (see createButton handler below).
use AppleScript version "2.4"
use framework "AppKit"
use framework "Foundation"
use scripting additions -- to show a dialog
property NSWindowController : class "NSWindowController"
property NSWindow : class "NSWindow"
property NSButton : class "NSButton"
property windowController : missing value
set theWindow to createWindowWithRect(0, 0, 500, 500)
set windowController to createWindowController(theWindow)
set theButton to createButton("Click me", 20, 20, 100, 24, "buttonAction:")
theWindow's contentView()'s addSubview:theButton
windowController's |window|()'s |center|()
my performSelectorOnMainThread:"showWindowSelector:" withObject:me waitUntilDone:true
return
on buttonAction:sender
display dialog "I'm clicked"
end buttonAction:
on createButton(title, xMin, yMin, xLen, yLen, selector)
set buttonSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
set theButton to NSButton's alloc()'s initWithFrame:buttonSize
theButton's setTitle:title
theButton's setBezelStyle:(current application's NSRoundedBezelStyle)
theButton's setAction:selector
theButton's setTarget:me
return theButton
end createButton
on createWindowWithRect(xMin, yMin, xLen, yLen)
set windowSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
set winStyle to (current application's NSWindowStyleMaskTitled) + (get current application's NSWindowStyleMaskClosable)
set aWindow to NSWindow's alloc()'s initWithContentRect:windowSize styleMask:winStyle backing:2 defer:yes
return aWindow
end createWindowWithRect
on createWindowController(aWindow)
set wController to NSWindowController's alloc()'s initWithWindow:aWindow
end createWindowController
on showWindowSelector:sender
windowController's |window|()'s makeKeyAndOrderFront:me
end showWindowSelector:
I already knew the base language of Objective-C (That is C) which made learning Objective-C quite easy but I have to give credits to Aaron Hillegass of The Big Nerd Ranch who beautifully explains the programming language. It was back in Panther days when I learned it, so my style of coding Objective-C is not the most modern (lazy) one. While most books explains how to use frameworks and it’s classes, which is irrelevant for learning of Objective-C, Aaron explains the design patterns behind it.
I strongly second DJ’s recommendation of Hillegass. I don’t know how up-to-date it is any more, but his ‘Cocoa Programming for Mac OS X’ was my bible. And if you have no C, the section in Matt Neuburg’s iOS book called something like ‘Just Enough C’ is worth tracking down.