First, it's been put in handlers: one to create the view, the existing one to show the dialog, and a third to retrieve the value from the popup. By putting it in handlers like this, confining all the ASObjC code to them, it can be stored in a script library and used under both Mavericks and Yosemite.
Second, the sizing of the label has been modified. The initial size is supplied (a width of 0), but then we get its fittingSize(), which tells us how big the text actually is, and then set the frame size to that, as well as using it to position the popup.
For the popup, we are setting its tag property. This is just an integer that we can later identify it with; the default value is -1, so we use 1. This enables the third handler to get the result, without requiring a reference to the popup -- it can just ask for the view's viewWithTag:1, and it will return the first item found in the accessory view with a tag of 1.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit" -- required for NSAlert, views and controls
-- check we are running in foreground
if not (current application's NSThread's isMainThread()) as boolean then
display alert "This script must be run from the main thread." buttons {"Cancel"} as critical
error number -128
end if
-- for styleNum, 0 = warning, 1 = informational, 2 = critical; for givingUpAfter, 0 means never; accessoryView of missing value means none
on displayAlert:mainText message:theExplanaton asStyle:styleNum buttons:buttonsList suppression:showSuppression givingUpAfter:giveUp accessoryView:theView
set buttonsList to reverse of buttonsList -- because they get added in reverse order cf AS
-- create an alert
set theAlert to current application's NSAlert's alloc()'s init()
-- set up alert
tell theAlert
its setAlertStyle:styleNum
its setMessageText:mainText
its setInformativeText:theExplanaton
repeat with anEntry in buttonsList
(its addButtonWithTitle:anEntry)
end repeat
its setShowsSuppressionButton:showSuppression
if theView is not missing value then its setAccessoryView:theView
end tell
-- if giveUp value > 0, tell the app to abort any modal event loop after that time, and thus close the panel
if giveUp > 0 then current application's NSApp's performSelector:"abortModal" withObject:(missing value) afterDelay:giveUp inModes:{current application's NSModalPanelRunLoopMode}
-- show alert in modal loop
set returnCode to theAlert's runModal()
-- if a giveUp time was specified and the alert didn't timeout, cancel the pending abort request
if giveUp > 0 and returnCode is not current application's NSModalResponseAbort then current application's NSObject's cancelPreviousPerformRequestsWithTarget:(current application's NSApp) selector:"abortModal" object:(missing value)
-- get values after alert is closed
set suppressedState to theAlert's suppressionButton()'s state() as boolean
set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button
if buttonNumber = 0 then
set buttonName to "Gave Up"
else
set buttonName to item buttonNumber of buttonsList
end if
return {buttonName, suppressedState}
end displayAlert:message:asStyle:buttons:suppression:givingUpAfter:accessoryView:
-- build the accessory view containing a label and popup menu
on accessoryViewWithLabel:theLabelText andPopUpList:listOfMenuItemNames
-- We can use any width for the label here
set theLabel to current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, 12, 0, 16))
tell theLabel
its setStringValue:theLabelText
its setEditable:false
its setBordered:false
its setDrawsBackground:false
-- get the size the label text fits in, and set the field's frame size to match
set theSize to its fittingSize()
its setFrameSize:theSize
end tell
-- create a popup to the right of the label, this time setting a fixed width of 100 pts
set thePopUp to current application's NSPopUpButton's alloc()'s initWithFrame:(current application's NSMakeRect(width of theSize, 10, 100, 20)) pullsDown:false
thePopUp's addItemsWithTitles:listOfMenuItemNames
thePopUp's setTag:1 -- so we can identify it later
-- create a view and add items
set theView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, 400, 40))
theView's setSubviews:{thePopUp, theLabel}
return theView
end accessoryViewWithLabel:andPopUpList:
-- retrieve the value of the popup
on chosenMenuItemInView:theView
return (theView's viewWithTag:1)'s title() as text
end chosenMenuItemInView:
-- create the accessory view
set theView to my accessoryViewWithLabel:"Choose a value:" andPopUpList:{"One", "Two", "Three", "Four"}
-- make the alert containing the view
set {buttonName, suppressedState} to (my displayAlert:"This is a dialog" message:"And this is the 9 o'clock news." asStyle:2 buttons:{"Cancel", "Maybe", "Possibly", "Probably", "OK"} suppression:false givingUpAfter:20.0 accessoryView:theView)
-- get the value of the popup
set chosenItem to my chosenMenuItemInView:theView
return {buttonName, chosenItem}