Extra buttons and suppression buttons are well and good, but things get more interesting when you start adding accessory views. This is similar to how it is done in open and save panels, except they appear above the buttons.
Different controls have different properties, and there are different ways of creating and positioning them. This script will use a label next to a popup menu.
The properties we set are whether it is in a box (setBordered:), whether the user can edit it (setEditable:), whether it draws a background (setDrawsBackground:), and its text (setStringValue:). We also set it's alignment so it appears next to the popup -- this is pretty rough positioning, but it will do for now.
Once the view has been dismissed, we ask for the popup's selectedTitleOfChoice.
Ideally this should all be done in handlers, but first off it's probably a bit easier to follow if it's done in a bit more linear fashion.
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
-- 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:
-- The accessory view will have a label followed by a popup menu
set theLabelText to "Choose a value from:"
-- rect values are trial and error for x, y, width, height, with y = 0 at the bottom
set theLabel to current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, 8, 200, 20))
tell theLabel
its setStringValue:theLabelText
its setEditable:false
its setBordered:false
its setDrawsBackground:false
its setAlignment:(current application's NSRightTextAlignment)
end tell
-- create a popup to the right of the label
set thePopUp to current application's NSPopUpButton's alloc()'s initWithFrame:(current application's NSMakeRect(200, 10, 100, 20)) pullsDown:false
thePopUp's addItemsWithTitles:{"One", "Two", "Three", "Four"}
-- 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}
-- pass the view to the alert handler
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)
set popupChoice to thePopUp's titleOfSelectedItem() as text
return {buttonName, popupChoice, suppressedState}