Hello, I just started playing with Dialog Toolkit and I was wondering if a choice from the popup list can trigger different fields. For example, referring to the complex sample in DT, I would like that when “Green” is selected in the popup some text fields are shown and switching to “Red” other fields appear. The same question can be transferred to checkboxes: my idea is the possibility to create a checkbox named “enable extra info” that shows extra fields only when selected. Thank you
The dialog/window content is performed by using an accessory view that contains a (bottom up) list of the controls, which are created and positioned by using the various library handlers with specified location offsets. There isn’t a handy way to dynamically repopulate or rearrange the list after it has been shown - maybe use an initial setup dialog that selects the control layout? It might be helpful to provide a control layout to show exactly what you are wanting to do.
Dynamically changing the controls may be possible, but it would be a bit of work. For example:
- Create controls to replace controls - they would need to be sized to keep from overwriting other controls.
- Hide controls - perhaps stack a set of hidden alternates in the same location and use a control to reveal one of them.
- Show all the alternate controls, enabling the desired controls as needed.
Also, there isn’t anything in the library or script for it to know if a control was changed, so you would need to add delegate or target/action handlers for the particular control in order to deal with that. Then you could replace/show or whatever when the control is used.
All of this is a little beyond what the Dialog Toolkit was designed to do, and starts getting into manually creating the UI, so I suppose it depends on how much you are wanting to put into it.
Hello red_menace, thank you for your reply.
I’m trying to build a unique simple script for me and my co-workers that unites and enhances some old basic scripts I wrote in AS that essentially were a long set of display dialogs whose inputs were put in an e-mail text and/or subject, so a very simple task to perform do in AS. Just for clarification I used them as Finder actions, I right clicked on the files that became attachments to the e-mail that was populated with some standard text and variables coming from the dialogs.
I have 3-4 similar scripts but with different dialogs, so my idea is to try to create a single window in which the user can enter the inputs required depending on which old script is substituting.
Here is my script, for the moment it does nothing except from showing a dialog, I’m working on getting the correct results in the format I will need for the main script, which I will copy from the old ones once I get a satisfactory dialog. The dialog is still incomplete (probably more fields will add or change positions), I tried to translate in english the labels. As said before, the main script will be pretty easy (essentially “tell application “Mail” to make new outgoing message with properties”)
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use script "Dialog Toolkit Plus" version "1.1"
use script "Dialog Toolkit Plus Extended" version "1.1"
set accViewWidth to 400
set allControls to {}
set startingDate to (current date)
set {theButtons, minWidth} to create buttons {"Cancel", "Create e-mail"} default button "Create e-mail" cancel button "Cancel" with equal widths
if minWidth > accViewWidth then set accViewWidth to minWidth
set theLabelStrings to {"", "Contractor:", "Extra notes:", "Amount due:", "Client:", "Invoice number:", "Date:"}
set maxLabelWidth to max width for labels theLabelStrings
set controlLeft to maxLabelWidth + 8
set {campoNote, etichettaNote, theTop, fieldLeft} to create side labeled field ("") placeholder text "" left inset 0 bottom 12 total width accViewWidth label text (item 3 of theLabelStrings) field left controlLeft
set {campoImporto, etichettaImporto, theTop, fieldLeft} to create side labeled field ("") placeholder text "" left inset 0 bottom (theTop + 12) total width accViewWidth label text (item 4 of theLabelStrings) field left controlLeft
set {campoNumero, etichettaNumero, theTop, fieldLeft} to create side labeled field ("") placeholder text "" left inset 0 bottom (theTop + 12) total width accViewWidth / 2 - 8 label text (item 6 of theLabelStrings) field left controlLeft
set {theCheckbox, theTop, newWidth} to create checkbox "Last one" bottom (theTop - 20) max width accViewWidth / 2 left inset accViewWidth / 2 + 40 without initial state
set {campoImpresa, etichettaImpresa, theTop, fieldLeft} to create side labeled field ("") placeholder text "" left inset 0 bottom (theTop + 12) total width accViewWidth label text (item 2 of theLabelStrings) field left controlLeft
set {campoCommittente, etichettaCommittente, theTop, fieldLeft} to create side labeled field ("") placeholder text "" left inset 0 bottom (theTop + 12) total width accViewWidth label text (item 5 of theLabelStrings) field left controlLeft
set newDateLabel to (item 7 of theLabelStrings)
set theLabelWidth to max width for labels {newDateLabel} control size regular size
set {theDateFieldLabel, theTop} to create label newDateLabel left inset 60 bottom (theTop + 12) max width maxLabelWidth control size regular size
set the end of allControls to theDateFieldLabel
set {theDateField, theTop} to create textual datepicker textual stepper picker elements YearMonthDay initial date startingDate min date seconds 0 max date seconds 0 left inset controlLeft bottom (theTop - 20) extra width 0 extra height 0
set the beginning of allControls to theDateField
set {SceltaOperazione, popupLabel, theTop} to create labeled popup {"Invoice authorization", "Invoice sending", "Retentions giveback"} left inset 0 bottom (theTop + 8) popup width 166 max width accViewWidth label text (item 1 of theLabelStrings) popup left controlLeft initial choice "Invoice authorization"
set allControls to {theCheckbox, SceltaOperazione, campoNote, etichettaNote, campoImporto, etichettaImporto, campoImpresa, etichettaImpresa, campoCommittente, etichettaCommittente, campoNumero, etichettaNumero, theDateField, theDateFieldLabel}
set {buttonName, controlsResults} to display extended window "Accounting" acc view width accViewWidth acc view height theTop acc view controls allControls buttons theButtons with align cancel button
set {Finale, OperazioneScelta, NoteOggetto, unused, ImportoSAL, unused, NomeImpresa, unused, NomeCommittente, unused, NumeroSAL, unused, DataEstesa, unused} to controlsResults
-- Set up a date parser to format the extended date string (e.g., "Lunedì 20 Ottobre 2025 alle ore 15:45:00 Ora legale dell’Europa centrale")
set parser to current application's NSDateFormatter's new()
set parser's locale to current application's NSLocale's localeWithLocaleIdentifier:"it_IT_POSIX"
set parser's dateFormat to "EEEE dd MMMM yyyy 'alle ore' HH:mm:ss 'Ora legale dell’Europa centrale'"
-- Helper function to adjust the timezone if necessary (switch from "Ora standard" to "Ora legale")
on adjustTimeZone(inputDate)
if inputDate contains "Ora standard" then
set inputDate to my replaceText("Ora standard dell’Europa centrale", "Ora legale dell’Europa centrale", inputDate)
end if
return inputDate
end adjustTimeZone
-- Helper function to replace a text substring with another (for adjusting the date string)
on replaceText(findText, replaceText, originalText)
set text item delimiters to findText
set textList to text items of originalText
set text item delimiters to replaceText
set newText to textList as text
set text item delimiters to {""} -- Reset the text delimiters
return newText
end replaceText
-- Attempt to parse the extended date string, adjusting timezone if needed
try
-- Adjust the timezone and parse the date string
set parsedTestDate to parser's dateFromString:(adjustTimeZone(DataEstesa))
-- Format the parsed date to the desired format (e.g., "dd/MM/yyyy")
set dateFormatter to current application's NSDateFormatter's new()
set dateFormatter's locale to current application's NSLocale's localeWithLocaleIdentifier:"it_IT"
set dateFormatter's dateFormat to "dd/MM/yyyy"
set dataScelta to (dateFormatter's stringFromDate:parsedTestDate) as text
on error errMsg
-- Return an error message if something goes wrong during date parsing
return "Error: " & errMsg
end try
return {Finale, OperazioneScelta, NoteOggetto, ImportoSAL, NomeImpresa, NomeCommittente, NumeroSAL, dataScelta}
Hoping that I pasted the right way (edit: now I think I have
), one thing I would like to obtain is that switching from “Invoice authorization” to “Retentions giveback” the field “invoice number” and the checkbox “last one” should disappear from the window, and reappear if I switch back to “invoice authorization” or “invoice sending”. Another nice upgrade would be to insert a checkbox that enables “extra notes”, and shows only if the user wants to add some extras.
Of course there will be many of these situations, but I think that learned the method once it will be easy to replicate.
On this forum I found an old topic of 2017 with a script that is dynamically changing the choice of a second popup based on the choice of another popup, but I don’t know if I can paste here since it’s not mine.
Last but not least, I know very little about AS and nothing about ASObjC, for the time being I’m only able to collect for existing scripts and trying to suit to my needs ![]()
The main issue with adding or changing the controls is that the alert/window draws them as they are passed. It is then difficult to change the layout, as everything needs to be done within the modal loop, with all controls available for the alert/window handler that is going to get all the values. It is a bit easier if the different controls can be placed in the same locations, then you don’t have to mess with any other controls to get it looking decent, you just need to manage their visibility. For example, the following uses multiple matrices that are similar so that they can be in the same location, with a popup button used to change which one is visible:
-- Sample showing how to use a control to change the visibility of another control.
-- Uses the Complex alert sample as a template.
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
use script "Dialog Toolkit Plus" version "1.1.0" -- should be in ~/Library/Script Libraries
global alternateControls -- this will be a dictionary of the alternate controls
on run -- example
set alternateControls to current application's NSMutableDictionary's dictionary
set theTop to 0
#1, #2 - order of controls in the `allControls` list below
set {thePathControl, pathLabel, theTop} to create labeled path control (POSIX path of (path to documents folder)) left inset 0 bottom (theTop + 12) control width 400 label text "Choose or drag the file here:" with pops up
#3
set {theRule, theTop} to create rule (theTop + 12) left inset 0 rule width 400
##### the following matrices are in the same location:
set theTop to theTop + 12
#4 - red
set {redMatrix, matrixLabel, newTop, matrixLeft} to create labeled matrix {"One", "Two", "Three"} left inset 0 bottom (theTop + 8) max width 400 matrix left 0 label text "Red Options:" initial choice 1
addAlternate("Red", redMatrix, 4)'s setHidden:true
#5 - green
set {greenMatrix, matrixLabel, newTop, matrixLeft} to create labeled matrix {"A", "B", "C"} left inset 0 bottom (theTop + 8) max width 400 matrix left 0 label text "Green Options:" initial choice 2
addAlternate("Green", greenMatrix, 5)'s setHidden:false
set defaultMatrix to "Green"
#6 - blue
set {blueMatrix, matrixLabel, newTop, matrixLeft} to create labeled matrix {"This", "That", "Other"} left inset 0 bottom (theTop + 8) max width 400 matrix left 0 label text "Blue Options:" initial choice 3
addAlternate("Blue", blueMatrix, 6)'s setHidden:true
#####
set theTop to newTop
#7 #8 - order of controls in the `allControls` list below
set {colorPopup, popupLabel, theTop} to create labeled popup {"Red", "Green", "Blue"} left inset 0 bottom (theTop + 8) popup width 100 max width 400 label text "Job is for:" popup left 150 initial choice defaultMatrix
colorPopup's setTarget:me
colorPopup's setAction:"popupAction:"
set allControls to {thePathControl, pathLabel, theRule, redMatrix, greenMatrix, blueMatrix, colorPopup, popupLabel}
set {buttonName, suppressedState, controlsResults} to display enhanced alert "Variable Control Test" message "" as critical alert buttons {"Cancel", "OK"} acc view width 400 acc view height theTop acc view controls allControls without suppression
# remove values of hidden matrices - NSIndexSet is used to remove multiple indexes at once
set indexSet to current application's NSMutableIndexSet's indexSet()
repeat with aKey in {"Red", "Green", "Blue"}
set isHidden to ((alternateControls's valueForKeyPath:("" & aKey & ".control"))'s isHidden) as boolean
if isHidden then (indexSet's addIndex:(((alternateControls's valueForKeyPath:("" & aKey & ".indexValue")) as integer) - 1))
end repeat
set controlsResults to current application's NSMutableArray's arrayWithArray:controlsResults
controlsResults's removeObjectsAtIndexes:indexSet
return {buttonName, suppressedState} & (controlsResults as list)
end run
# Add an alternate matrix to the dictionary - returns the control to set properties.
to addAlternate(keyName, control, indexValue)
set object to current application's NSDictionary's dictionaryWithDictionary:{control:control, indexValue:indexValue}
alternateControls's setValue:object forKey:keyName
return control
end addAlternate
# Change matrix control visibility based on popup value.
on popupAction:sender
repeat with aKey in {"Red", "Green", "Blue"}
((alternateControls's valueForKeyPath:("" & aKey & ".control"))'s setHidden:true)
end repeat
(alternateControls's valueForKeyPath:(((sender's title) as text) & ".control"))'s setHidden:false
end popupAction:
I would need to install the extended libraries to check, but if you are moving stuff around, if you can rearrange things so that the alternate stuff with the selection control occupies a similar space it will make things a lot easier.
Thank you very much for your reply and your script.
Your solution is for sure an upgrade, since it can show different matrixes based on a popup choice, so this is a nice starting point.
This gave me an idea: instead of making labels appear/disapper based on choices that can mess with overlappings, what would happen if we totally write three different sets of labels/checkboxes and whatever I need to be shown based on the popup choice? Maybe it’s not the best optimized way but…“if it’s ******* but it works, it ain’t *******”
The main thing to keep in mind is that you pretty much need to create everything and have it available, since you are working inside a modal loop and the library alert/window needs to know what all the controls are. If the plan is to stick with the Dialog Toolkit, you are going to be limited to what it provides.
When trying to combine multiple dialogs, one idea would be to find what is common and create those items first, then see if the different stuff can be arranged to fit into a similar area so that the different groupings can be enabled or made visible without having to worry about rearranging anything else.
Trying to maximize the number of common dialogs and fit the others in similar areas can be an option, but if I learn how to manage the dialogs to be totally independent I may not mind on create 3x or 4x the variables, the problem is that I don’t even know how to start.
If I correctly understood what you are trying to explain to me, the main problem of writing totally different set of dialogs and similar arises when one set of dialogs (triggered by first popup choice) requires a dialog window of different size respect to the second set of dialogs (triggered by second popup choice), right? In this case, wouldn’t be an easy solution to set the size of the window as the maximum between the popup choices dialogs set?
As an example, how can I simplify, if this can be done, the script to remove the labeled path control (I don’t need in this script) and show two dialogs for the “Green” and, let’s say, two dialogs and a checkbox for the “Blue”? For the script that I have in mind I will only need dialogs and checkboxes beyond the initial choice made by the initial popup.
I think that with this template (if I can understand a little how it works, which is not guaranteed at all
), and once I learn how I can add dialogs where I want, I can try to build all the different combination that I need for my script
What I have been describing so far is using the Dialog Toolkit to have everything in the same dialog, but showing different pieces depending on a control setting (popup button, etc). Without extending the library script, there isn’t access to the window or alert, so there isn’t much you can do to change the control layout or arrangement of the currently running dialog. If you are wanting to do something like have a main dialog that is used to get some common data and then choose other sub dialogs that have different control layouts, that can also be done, but depending on exactly how different the layouts are, “death by dialog” can just become “seriously wounded by dialog”.
Since the control visibility is one of the properties that can be useful, my idea so far has been to arrange sets of alternate controls so that they can be grouped into the same space, since it is problematic to rearrange or move the controls once they have been created. Multiple groups of controls (not just a single control) can be made visible as desired by various other controls, but it depends a bit on the control layouts being similar enough so that the changes make some sense. For an example that combines your last few responses, in the following script some common items are above the rule, while the area below the rule is sized to contain the alternate controls, which are shown according to the popup button:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use script "Dialog Toolkit Plus" version "1.1"
use script "Dialog Toolkit Plus Extended" version "1.1" -- datePicker
property popupItems : {"This Thing", "That Thing", "The Other Thing"} -- the operations to perform
global controlGroups -- this will be a dictionary of the alternate groups and their controls
on run -- example
set controlGroups to current application's NSMutableDictionary's dictionary -- for using a keyPath
set {viewWidth, theTop} to {400, 28}
# controls are stacked from the bottom up for easier vertical positioning
set {theButtons, minWidth} to create buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with equal widths
if minWidth > viewWidth then set viewWidth to minWidth
set {maxLabelWidth, controlLeft} to {100, 110}
########## begin control group #1 - these are layered in the same space, with only the active alternate shown
set newTop to theTop -- alternate A (This Thing)
set {A2_textField, A2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop) total width viewWidth label text "This #2:" field left controlLeft
set {A1_textField, A1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "This #1:" field left controlLeft
repeat with anItem in (addAlternate(1, first item of popupItems, {A1_textField, A1_labelField, A2_textField, A2_labelField}))
(anItem's setHidden:true)
end repeat
----
set newTop to theTop -- alternate B (That Thing)
set {B3_checkbox, newTop, newWidth} to create checkbox "That Checkbox" bottom (newTop - 24) max width (viewWidth / 2) left inset controlLeft without initial state
set {B2_textField, B2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #2:" field left controlLeft
set {B1_textField, B1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #1:" field left controlLeft
repeat with anItem in (addAlternate(1, second item of popupItems, {B1_textField, B1_labelField, B2_textField, B2_labelField, B3_checkbox}))
(anItem's setHidden:true)
end repeat
########## end control group #1
set theTop to newTop -- continue from previous top
set {divider, theTop} to create rule (theTop + 12) rule width viewWidth -- NSBox
set {invoiceTextField, invoiceLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width (viewWidth / 2) label text "Invoice number:" field left controlLeft
set {contractorTextField, contractorLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width viewWidth label text "Contractor:" field left controlLeft
set {clientTextField, clientLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width viewWidth label text "Client:" field left controlLeft
set {dateLabelField, theTop} to create label " Date:" left inset 60 bottom (theTop + 12) max width maxLabelWidth control size regular size
set {datePicker, theTop} to create textual datepicker textual stepper picker elements YearMonthDay initial date (current date) min date seconds 0 max date seconds 0 left inset controlLeft bottom (theTop - 20) extra width 0 extra height 0
set {operationPopup, theTop} to create popup popupItems left inset controlLeft bottom (theTop + 8) popup width 180 initial choice (last item of popupItems)
operationPopup's setToolTip:"the operation to perform"
operationPopup's setTarget:me
operationPopup's setAction:"popupAction:" -- choose from group #1
set allControls to {operationPopup, dateLabelField, datePicker, clientLabelField, clientTextField, contractorLabelField, contractorTextField, invoiceLabelField, invoiceTextField, divider, A1_labelField, A1_textField, A2_labelField, A2_textField, B1_labelField, B1_textField, B2_labelField, B2_textField, B3_checkbox} -- control references are listed from top to bottom for easier indexing
set {buttonName, controlValues} to display extended window "Descriptive Title" acc view width viewWidth acc view height theTop acc view controls allControls buttons theButtons without align cancel button
doStuff for (formatResult from controlValues)
end run
# Extract the desired controls from the returned dialog values and group into a record.
to formatResult from dialogResult
tell (date (item 3 of dialogResult) as «class isot» as string) to set ISODate to text 9 thru 10 & "/" & text 6 thru 7 & "/" & text 1 thru 4 -- format date using the built-in ISO date class (no time zone info)
tell dialogResult -- use record for consistent key:value pairs
set common to {operation:item 1, theDate:ISODate, client:item 5, contractor:item 7, invoice:item 9} -- common items
if first item is first item of popupItems then -- common + alternate A
set results to common & {A1_textField:item 12, A2_textField:item 14}
else if first item is second item of popupItems then -- common + alternate B
set results to common & {B1_textField:item 16, B2_textField:item 18, B3_checkbox:item 19}
else if first item is third item of popupItems then
set results to common
else -- oops
set results to missing value
end if
end tell
return results
end formatResult
# Add a set of alternate controls to the controlGroups dictionary - controls are returned for any customization.
to addAlternate((group as text), (keyName as text), (controls as list))
if (controlGroups's valueForKey:group) is missing value then (controlGroups's setValue:(current application's NSMutableDictionary's dictionary()) forKey:group) -- add new group as needed
controlGroups's setValue:(current application's NSDictionary's dictionaryWithDictionary:{controls:controls}) forKeyPath:(group & "." & keyName) -- add keyName alternate controls to group
return controls
end addAlternate
# Action to change the visibility of group #1 controls based on the popup value.
on popupAction:sender
repeat with aKey in popupItems -- hide everything
set controlList to (controlGroups's valueForKeyPath:("1." & aKey & ".controls"))
if controlList is not missing value then repeat with aControl in controlList
((contents of aControl)'s setHidden:true)
end repeat
end repeat
set controlList to (controlGroups's valueForKeyPath:("1." & ((sender's title) as text) & ".controls"))
if controlList is not missing value then repeat with aControl in controlList -- show the selected control group
((contents of aControl)'s setHidden:false)
end repeat
end popupAction:
# Do stuff for the dialog result values.
to doStuff for dialogValues
tell (operation of dialogValues) to if it is first item of popupItems then
-- perform `This` with dialogValues for this operation
else if it is second item of popupItems then
-- perform `That` with dialogValues for that operation
else if it is third item of popupItems then
-- perform `The Other` with dialogValues for the other operation
end if
return dialogValues
end doStuff
There are a few more details to work out, such as arranging the results (variables) based on the different layouts, but this should be something to start with.
Script edited for:
- Additional comments
- Updated variable names and text to be more generic
- Added support for multiple control groups
- Item indexes used instead of hidden control deletion with NSIndexSet
Thank you very much, I think that there is a lot of potential in the script you provided, now I try to study it and try to understand how it works to apply the changes I need!
What do you mean with “extending the library script”? Are there some alternatives that can help me achieve the result I’m looking for? I’m not necessarily stuck with Dialog Toolkit once I find alternatives that can show the same results (starting from a finder quick action)
Don’t know if it will meet your needs but there is
and usage examples for it
Hello pjh,
this is a very nice solution that mostly seems to be configurable as I would like to.
At a first look, one thing that seems to be missing is a datepicker, which in my case would be very useful to avoid mistypings…hope that this can be done and I didn’t spot it in the documentation!
Edit: turns out that a basic way on inputing dates in swiftdialog has been added, if it works as I would expect this is definitively worth a try!
Sources for Dialog ToolKit Plus and SwiftDialog are available so that they can be modified/extended, like the DT+ extension that provides Date Pickers, although SwiftDialog is built with Xcode (and uses Swift). SwiftDialog (and pretty much any other external script/app) also has the same limitation in that once the dialog is running there isn’t a handy way to dynamically access the window or rearrange the controls (which for SwiftDialog are set using command line arguments or JSON). About the only way around that is to have your script/app create the entire UI by itself and be structured to provide that ability.
Dialog Toolkit does a lot of the heavy lifting for you, but if you wanted to use something else you can always use the Cocoa frameworks like regular applications do. AppleScriptObj-C can be used to access the Cocoa frameworks from AppleScript, and there are a few other languages that also provide access with varying amounts of hair loss such as JXA or PyObjC (I am staying away from Swift). In addition to knowing these languages and their development environments, you would need to get familiar with the Cocoa frameworks, so there is a bit of a learning curve (I am also deliberately staying away from Xcode, which has its own learning curve).
I’ve updated my previous script to (hopefully) make it a little easier to follow what it is doing.
Thank you for your explanation, now I understand what you meant with “extending the library script”. Unfortunately it’s for sure way beyond my abilities to learn a programming language and how to develop using it.
I didin’t know SwiftDialog, so I tried it to see if it can suit my needs. After some very basic tests, turns out that is quite easy to setup a single UI like in DT, and I found an AS script that shows me how to run the dialog and get the results inside variables I can use later for other tasks. I also noticed that some elements can be changed on the fly while the dialog is already showing (titles, backgrounds, button names, window sizes), and I was very happy about this possibility, but I didn’t find any mention about showing/hiding checkboxes and/or textfields
I felt like being capped at 95%
. I opened an issue on GitHub to see if someone has a suggestion for this
About the script edit, I really appreciate it, and I will make for sure some experiments to see if I can edit to suit my needs!
Will report back if I have updates either from your script or SwiftDialog
I think that the updated script is almost a solution for me, since I was able to add checkboxes, date fields, textfields to different popup choices ![]()
Now I have another problem, but it’s due to my lack of knowledge and I’m sure that can be solved in one row addition:
How can I return the value of a single variable (let’s say B2_textfield)?
At the very end I will have something like:
tell application "Mail"
activate
set theContent to "Test content"
set theMessage to make new outgoing message with properties {subject:"test", content:theContent, visible:true}
where I would like to have the value of B2_textfield as subject in the email instead of word “test”, how can I achieve this?
I don’t know the changes you have made, or if you have made matching changes to the formatResult handler (to extract other item values and add them to the result record) or the doStuff hander (to deal with the operation value and do stuff directly or pass the record to something else), so I will use my posted script.
Statements can be added to the doStuff handler to do stuff with the dialogValues record (which is the controlValues result from the DT+ window), or if there is a bunch of stuff to do, the record can be passed to another handler to do the stuff with it. In the posted script’s doStuff handler, the dialogResult record will have an operation label with a value of “That Thing” (the second item of popupItems), which evaluates to the That part of the if statement (note that this if statement is in a tell statement). This record would also have a B2_textfield labeled item, so in that handler, it would be something like:
-- snip --
else if it is second item of popupItems then -- perform `That` with dialogValues
tell application "Mail"
activate
set theContent to "Test content"
set theMessage to make new outgoing message with properties {subject:(B2_textField of dialogValues), content:theContent, visible:true}
end tell
-- snip --
that worked, thank you
Now I have another problem, I think I figured out what’s the cause, but I don’t know how to solve ![]()
This script goes into Automator, so it will be used as Finder action that takes input and passes it to the script
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use script "Dialog Toolkit Plus" version "1.1"
use script "Dialog Toolkit Plus Extended" version "1.1" -- datePicker
property popupItems : {"A", "B", "C"} -- the operations to perform
global controlGroups -- this will be a dictionary of the alternate groups and their controls
on run {input, parameters}
set controlGroups to current application's NSMutableDictionary's dictionary -- for using a keyPath
set {viewWidth, theTop} to {400, 10}
# controls are stacked from the bottom up for easier vertical positioning
set {theButtons, minWidth} to create buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with equal widths
if minWidth > viewWidth then set viewWidth to minWidth
set {maxLabelWidth, controlLeft} to {100, 110}
########## begin control group #1 - these are layered in the same space, with only the active alternate shown
set newTop to theTop -- alternate A (This Thing)
set {A2_textField, A2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom 0 total width viewWidth label text "This #2:" field left controlLeft
set {A1_textField, A1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 12) total width viewWidth label text "This #1:" field left controlLeft
set {dateLabelFieldA, theTop} to create label " Data:" left inset 60 bottom (newTop + 12) max width maxLabelWidth control size regular size
set {datePickerA, theTop} to create textual datepicker textual stepper picker elements YearMonthDay initial date (current date) min date seconds 0 max date seconds 0 left inset controlLeft bottom (newTop + 8) extra width 0 extra height 0
repeat with anItem in (addAlternate(1, first item of popupItems, {A1_textField, A1_labelField, A2_textField, A2_labelField, dateLabelFieldA, datePickerA}))
(anItem's setHidden:false)
end repeat
----
set newTop to theTop -- alternate B (That Thing)
set {B3_checkbox, newTop, newWidth} to create checkbox "That Checkbox" bottom 0 max width (viewWidth / 2) left inset controlLeft without initial state
set {B2_textField, B2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #2:" field left controlLeft
set {B1_textField, B1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #1:" field left controlLeft
repeat with anItem in (addAlternate(1, second item of popupItems, {B1_textField, B1_labelField, B2_textField, B2_labelField, B3_checkbox}))
(anItem's setHidden:true)
end repeat
########## end control group #1
set newTop to theTop -- alternate C (That Thing)
set {C3_checkbox, newTop, newWidth} to create checkbox "That Checkbox C" bottom 0 max width (viewWidth / 2) left inset controlLeft without initial state
set {C2_textField, C2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 12) total width viewWidth label text "That #2:" field left controlLeft
set {dateLabelFieldC, theTop} to create label " Data:" left inset 60 bottom (newTop + 12) max width maxLabelWidth control size regular size
set {datePickerC, theTop} to create textual datepicker textual stepper picker elements YearMonthDay initial date (current date) min date seconds 0 max date seconds 0 left inset controlLeft bottom (newTop + 8) extra width 0 extra height 0
set {C1_textField, C1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 40) total width viewWidth label text "That #1:" field left controlLeft
repeat with anItem in (addAlternate(1, third item of popupItems, {C1_textField, C1_labelField, C2_textField, C2_labelField, C3_checkbox, dateLabelFieldC, datePickerC}))
(anItem's setHidden:true)
end repeat
########## end control group #1
set {operationPopup, theTop} to create popup popupItems left inset controlLeft bottom 120 popup width 180 initial choice (first item of popupItems) --modifica il valore bottom
operationPopup's setToolTip:"the operation to perform"
operationPopup's setTarget:me
operationPopup's setAction:"popupAction:" -- choose from group #1
set allControls to {operationPopup, A1_labelField, A1_textField, A2_labelField, A2_textField, B1_labelField, B1_textField, B2_labelField, B2_textField, B3_checkbox, C1_textField, C1_labelField, C2_textField, C2_labelField, C3_checkbox, dateLabelFieldA, datePickerA, dateLabelFieldC, datePickerC}
set {buttonName, controlValues} to display extended window "Descriptive Title" acc view width viewWidth acc view height theTop acc view controls allControls buttons theButtons without align cancel button
doStuff for (formatResult from controlValues)
end run
# Extract the desired controls from the returned dialog values and group into a record.
to formatResult from dialogresult
tell (date (item 17 of dialogresult) as «class isot» as string) to set ISODateA to text 9 thru 10 & "/" & text 6 thru 7 & "/" & text 1 thru 4 -- format date using the built-in ISO date class (no time zone info)
tell (date (item 19 of dialogresult) as «class isot» as string) to set ISODateC to text 9 thru 10 & "/" & text 6 thru 7 & "/" & text 1 thru 4 -- format date using the built-in ISO date class (no time zone info)
tell dialogresult -- use record for consistent key:value pairs
if first item is first item of popupItems then -- common + alternate A
set results to {operation:item 1, A1_textField:item 3, A2_textField:item 5, datePickerA:ISODateA}
else if first item is second item of popupItems then -- common + alternate B
set results to {operation:item 1, B1_textField:item 7, B2_textField:item 9, B3_checkbox:item 10}
else if first item is third item of popupItems then
set results to {operation:item 1, C1_textField:item 11, C2_textField:item 13, C3_checkbox:item 15, datePickerC:ISODateC}
else -- oops
set results to missing value
end if
end tell
return results
end formatResult
# Add a set of alternate controls to the controlGroups dictionary - controls are returned for any customization.
to addAlternate((group as text), (keyName as text), (controls as list))
if (controlGroups's valueForKey:group) is missing value then (controlGroups's setValue:(current application's NSMutableDictionary's dictionary()) forKey:group) -- add new group as needed
controlGroups's setValue:(current application's NSDictionary's dictionaryWithDictionary:{controls:controls}) forKeyPath:(group & "." & keyName) -- add keyName alternate controls to group
return controls
end addAlternate
# Action to change the visibility of group #1 controls based on the popup value.
on popupAction:sender
repeat with aKey in popupItems -- hide everything
set controlList to (controlGroups's valueForKeyPath:("1." & aKey & ".controls"))
if controlList is not missing value then repeat with aControl in controlList
((contents of aControl)'s setHidden:true)
end repeat
end repeat
set controlList to (controlGroups's valueForKeyPath:("1." & ((sender's title) as text) & ".controls"))
if controlList is not missing value then repeat with aControl in controlList -- show the selected control group
((contents of aControl)'s setHidden:false)
end repeat
end popupAction:
# Do stuff for the dialog result values.
to doStuff for dialogValues
tell (operation of dialogValues) to if it is first item of popupItems then
tell application "Mail"
activate
set theContent to "content"
set theAttachments to input
set theMessage to make new outgoing message with properties {subject:(A2_textField of dialogValues), content:theContent, visible:true}
tell theMessage
repeat with theAttachment in theAttachments
make new attachment with properties {file name:theAttachment as alias} at after last paragraph
end repeat
end tell
end tell
else if it is second item of popupItems then
tell application "Mail"
activate
set theContent to "content"
set theAttachments to input
set theMessage to make new outgoing message with properties {subject:(B2_textField of dialogValues), content:theContent, visible:true}
tell theMessage
repeat with theAttachment in theAttachments
make new attachment with properties {file name:theAttachment as alias} at after last paragraph
end repeat
end tell
end tell
else if it is third item of popupItems then
tell application "Mail"
activate
set theContent to "content"
set theAttachments to input
set theMessage to make new outgoing message with properties {subject:(C2_textField of dialogValues), content:theContent, visible:true}
tell theMessage
repeat with theAttachment in theAttachments
make new attachment with properties {file name:theAttachment as alias} at after last paragraph
end repeat
end tell
end tell
end if
return dialogValues
end doStuff
Variable input is not defined, and I think it’s because it’s used outside the main run handler. With (choose file) I could add an attachment, but it’s not how it’s supposed to work.
I hope that this is the last big problem I encounter; the remaining work will be the final adjustment of the dialog window with the correct textfields and checkboxes and transferring some subroutines that I used in the previous version of the script, so I think it should be all straightforward
Correct - the input parameter is local to the run handler. The easiest fix would probably be to save input into a global variable.
If you declare another global variable named theAttachments, and in the run handler set it to input, you could then remove all the set theAttachments to input statements in the doStuff handler.
This worked
Now that I should have all the tools I need, I will spend some time setting all up, but the good thing is that it’s a little more clear how the script works
Thank you for your time
I’m late to this discussion so, but hope this is still helpful. Back in 2017 and 2020 the idea of dynamically changing UI elements in DTP dialogs came up. Here are two of the discussions:
Sorry TL;DR – someone created this very nice example:
property ordersNmethods : {}
set ordersNmethods to {theOrders:{"Please Make a Selection", "Order Number 1, Production Method 2", "Order Number 2, Production Method 5"}, theMethods:{missing value, 2, 5}}
set {theButtons, minWidth} to create buttons {"Cancel", "OK"}
set {methodPopup, methodPopupLabel, theTop, matrixLeft} to create labeled popup {"1 - Some Method", "2 - Another Method", "3 - Still More Methods", "4 - The Rhythm Method", "5 - Methodical"} left inset 0 bottom 0 popup width 200 max width 400 label text "Override Method" popup left 0
set {orderPopup, orderPopupLabel, theTop, matrixLeft} to create labeled popup (theOrders of ordersNmethods) left inset 0 bottom (theTop + 20) popup width 200 max width 400 label text "Choose an Order" popup left 0
orderPopup's setTarget:me
orderPopup's setAction:"setMethod:"
set {buttonName, suppressedState, controlsResults} to display enhanced window "Test of a window" buttons theButtons giving up after 120 acc view width 700 acc view height (theTop + 10) acc view controls {methodPopup, orderPopup} without suppression
on setMethod:sender
set selectedOrderIndex to (my orderPopup's indexOfSelectedItem() as integer) + 1
set orderMethod to item selectedOrderIndex of theMethods of ordersNmethods
my (methodPopup's selectItemAtIndex:(orderMethod - 1))
end setMethod:
Can confirm it still works in macOS Tahoe.
Thank you for your help Neophyte, I saved your links just in case I will need them in the future!
I am literally two steps away from completing my first version to test, but I am encountering a little difficulty: let’s say I want to convert A1_textField to a currency value. In my old script I used the suggestion from Apple website, but I can’t understand how to use here. I think it’s due to a wrong positioning of the function. This is the point where I am stuck, transferred to the example script:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use script "Dialog Toolkit Plus" version "1.1"
use script "Dialog Toolkit Plus Extended" version "1.1" -- datePicker
property popupItems : {"This Thing", "That Thing", "The Other Thing"} -- the operations to perform
global controlGroups -- this will be a dictionary of the alternate groups and their controls
on convertNumberToCurrencyString(theNumber)
set theStyle to NSNumberFormatterCurrencyStyle of current application
set theFormattedNumber to localizedStringFromNumber_numberStyle_(theNumber, theStyle) of NSNumberFormatter of current application
return (theFormattedNumber as string)
end convertNumberToCurrencyString
on run -- example
set controlGroups to current application's NSMutableDictionary's dictionary -- for using a keyPath
set {viewWidth, theTop} to {400, 28}
# controls are stacked from the bottom up for easier vertical positioning
set {theButtons, minWidth} to create buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" with equal widths
if minWidth > viewWidth then set viewWidth to minWidth
set {maxLabelWidth, controlLeft} to {100, 110}
########## begin control group #1 - these are layered in the same space, with only the active alternate shown
set newTop to theTop -- alternate A (This Thing)
set {A2_textField, A2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop) total width viewWidth label text "This #2:" field left controlLeft
set {A1_textField, A1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "This #1:" field left controlLeft
repeat with anItem in (addAlternate(1, first item of popupItems, {A1_textField, A1_labelField, A2_textField, A2_labelField}))
(anItem's setHidden:true)
end repeat
----
set newTop to theTop -- alternate B (That Thing)
set {B3_checkbox, newTop, newWidth} to create checkbox "That Checkbox" bottom (newTop - 24) max width (viewWidth / 2) left inset controlLeft without initial state
set {B2_textField, B2_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #2:" field left controlLeft
set {B1_textField, B1_labelField, newTop, fieldLeft} to create side labeled field ("") left inset 0 bottom (newTop + 6) total width viewWidth label text "That #1:" field left controlLeft
repeat with anItem in (addAlternate(1, second item of popupItems, {B1_textField, B1_labelField, B2_textField, B2_labelField, B3_checkbox}))
(anItem's setHidden:true)
end repeat
########## end control group #1
set theTop to newTop -- continue from previous top
set {divider, theTop} to create rule (theTop + 12) rule width viewWidth -- NSBox
set {invoiceTextField, invoiceLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width (viewWidth / 2) label text "Invoice number:" field left controlLeft
set {contractorTextField, contractorLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width viewWidth label text "Contractor:" field left controlLeft
set {clientTextField, clientLabelField, theTop, fieldLeft} to create side labeled field ("") bottom (theTop + 12) total width viewWidth label text "Client:" field left controlLeft
set {dateLabelField, theTop} to create label " Date:" left inset 60 bottom (theTop + 12) max width maxLabelWidth control size regular size
set {datePicker, theTop} to create textual datepicker textual stepper picker elements YearMonthDay initial date (current date) min date seconds 0 max date seconds 0 left inset controlLeft bottom (theTop - 20) extra width 0 extra height 0
set {operationPopup, theTop} to create popup popupItems left inset controlLeft bottom (theTop + 8) popup width 180 initial choice (last item of popupItems)
operationPopup's setToolTip:"the operation to perform"
operationPopup's setTarget:me
operationPopup's setAction:"popupAction:" -- choose from group #1
set allControls to {operationPopup, dateLabelField, datePicker, clientLabelField, clientTextField, contractorLabelField, contractorTextField, invoiceLabelField, invoiceTextField, divider, A1_labelField, A1_textField, A2_labelField, A2_textField, B1_labelField, B1_textField, B2_labelField, B2_textField, B3_checkbox} -- control references are listed from top to bottom for easier indexing
set {buttonName, controlValues} to display extended window "Descriptive Title" acc view width viewWidth acc view height theTop acc view controls allControls buttons theButtons without align cancel button
doStuff for (formatResult from controlValues)
end run
# Extract the desired controls from the returned dialog values and group into a record.
to formatResult from dialogResult
tell (date (item 3 of dialogResult) as «class isot» as string) to set ISODate to text 9 thru 10 & "/" & text 6 thru 7 & "/" & text 1 thru 4 -- format date using the built-in ISO date class (no time zone info)
tell dialogResult -- use record for consistent key:value pairs
set common to {operation:item 1, theDate:ISODate, client:item 5, contractor:item 7, invoice:item 9} -- common items
if first item is first item of popupItems then -- common + alternate A
set results to common & {A1_textField:item 12, A2_textField:item 14}
else if first item is second item of popupItems then -- common + alternate B
set results to common & {B1_textField:item 16, B2_textField:item 18, B3_checkbox:item 19}
else if first item is third item of popupItems then
set results to common
else -- oops
set results to missing value
end if
end tell
return results
end formatResult
# Add a set of alternate controls to the controlGroups dictionary - controls are returned for any customization.
to addAlternate((group as text), (keyName as text), (controls as list))
if (controlGroups's valueForKey:group) is missing value then (controlGroups's setValue:(current application's NSMutableDictionary's dictionary()) forKey:group) -- add new group as needed
controlGroups's setValue:(current application's NSDictionary's dictionaryWithDictionary:{controls:controls}) forKeyPath:(group & "." & keyName) -- add keyName alternate controls to group
return controls
end addAlternate
# Action to change the visibility of group #1 controls based on the popup value.
on popupAction:sender
repeat with aKey in popupItems -- hide everything
set controlList to (controlGroups's valueForKeyPath:("1." & aKey & ".controls"))
if controlList is not missing value then repeat with aControl in controlList
((contents of aControl)'s setHidden:true)
end repeat
end repeat
set controlList to (controlGroups's valueForKeyPath:("1." & ((sender's title) as text) & ".controls"))
if controlList is not missing value then repeat with aControl in controlList -- show the selected control group
((contents of aControl)'s setHidden:false)
end repeat
end popupAction:
# Do stuff for the dialog result values.
to doStuff for dialogValues
tell (operation of dialogValues) to if it is first item of popupItems then
return convertNumberToCurrencyString((A2_textField of dialogValues))
else if it is second item of popupItems then
-- perform `That` with dialogValues for that operation
else if it is third item of popupItems then
-- perform `The Other` with dialogValues for the other operation
end if
return dialogValues
end doStuff
The second step will probably be: how can I check if the input entered in A2_textfield is a number (was not mistyped inserting a letter) and, if it’s not, give an error dialog and get back to the main dialog window?
Thank you very much