Copy link to clipboard
Copied
I have a script that loads a .tpl file from a specified location
toolPresetFile = new File("/path/to/file");
app.load(toolPresetFile);
This seems to work silently without problems in CS4 up until CC 2017. In CC 2018, when trying to load the .tpl file, I get the following dialog.
There are 3 presets inside this file, and it is important that they all Load as Tools (and not be imported as brushes), because of something particular to my workflow.
Ideally I would like to prevent this suggestion from appearing at all, and Load as Tools by default.
As suggested in How to avoid modal dialogs from blocking script execution , I have tried doing:
app.displayDialogs = DialogModes.NO;
[my code to load the .tpl file]
app.displayDialogs = DialogModes.ERROR;
This did not work, this particular warning/suggestion dialog seems unavoidable and I have not been able to find a way to suppress or bypass it (yes, checking off Don't show again would be a solution, but I want it to be so that a user using the script for the first time never has to deal with any dialog interruption when running the script).
What I am looking for now, is a way to detect this dialog from within the script, and automatically choose Load as Tools without the user having to click on anything. Is this possible?
If not, does anyone know of a way to force a tpl file to load as type 'tool presets' and bypass Photoshop CC 2018's suggestion about brush presets?
And like this? )
...toolPresetFile = new File("/path/to/file");
load_preset(toolPresetFile, true)
function load_preset(file, add)
{
try
{
var r = new ActionReference();
r.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID( "toolPreset" ) );
r.putEnumerated( charIDToTypeID( "capp" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var d = new ActionDescriptor();
d.putReference( charIDToTypeID( "null" ), r );
Copy link to clipboard
Copied
Change your code to this:
File((fNp = File($.fileName).path) + '/box.exe').execute(), load(File(fNp + "/tpl.tpl"))
It executes box.exe file that has to be in the same folder your script is. Then it loads your .tpl file (change name to desired) which has to be in the same script folder. It is because $.fileName is a command of full path (including file name) of script you're running.
.exe file is an compiled .ahk file with autohotkey.com Windows OS programming language which I used to wrote this:
sleep 25
send {right}
send {right}
send {Enter}
return
I don't have CC2018, but experienced same problem howerver needed only one automatically pressed right button. In your case that should be two (or {tab} for tabulator). If a time of waiting for loading .tpl file you'll see is to short then you have to play with changing it to higher value about each 25 miliseconds (so 25 / 1000 of one second). Maybe there will be also need to add some micro sleep command between send keys. If so edit the code and compile to exe (you select it right clicking on a .ahk file in your system and then selecting new option 'Compile Script' (2nd from up). To do this all just download newest version of AHK from a site I gave link to. Or you can use DropBox link I attach below to check .exe with the content I posted works for you after all.
Personally I use it in many of my scripts always when sole Ps scripting knowledge can't be of help to achieve my goals. Examplary usage of AHK combined with Scripted Photoshop Dialog and Event you find in ones of my latest posts on this forum: UI set Caret position in editText control and options of info panel. / here you find a file: Dropbox - box.exe
Copy link to clipboard
Copied
try this )
toolPresetFile = new File("/path/to/file");
load_preset(toolPresetFile)
function load_preset(file)
{
try
{
var r = new ActionReference();
r.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID( "toolPreset" ) );
r.putEnumerated( charIDToTypeID( "capp" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var d = new ActionDescriptor();
d.putReference( charIDToTypeID( "null" ), r );
d.putPath( charIDToTypeID( "T " ), file );
executeAction( charIDToTypeID( "setd" ), d, DialogModes.NO );
}
catch(e) { alert(e); }
}
Copy link to clipboard
Copied
Thanks! This actually works quite well in terms of silencing the dialog. The only small issue is that it removes all other tool presets that had been previously loaded in the tool preset panel, i.e. it does something similar to when one clicks on 'Replace Tool Presets...' instead of 'Load Tool Presets...'
Any ideas? I am thinking maybe a slight adjustment to one of the charID values, I will keep researching.
This has definitely pointed me in the right direction, thank you very much!
Copy link to clipboard
Copied
Using Action Manager you can't load Brush / Tool presets, only replace them. It's why I proposed you my method. I noticed that some warnings doesn't pop up when you do the same action by scripting. So if there is something done by user in Ps you'll see dialog (and I'm not saying about setting DialogModes. to ALL / NO). I wasn't sure how it's in CC2018 but assumed it works the same like in previous versions, so in some cases you won't be asked of additional stuff when you do the same thing using script.
That ahk script if rewritten a little can be expanded also to cover situation when an user chcecked "Don't show agian" box. So it won't make any harm playing its commands when dialog does not pop up. However there is even better way where ahk checks name of current dialog. Then either it executes those commands of script I wrote or simply exits its process. Let me know you want this functionality if you're not happy with replacing instead of loading...
Copy link to clipboard
Copied
And like this? )
toolPresetFile = new File("/path/to/file");
load_preset(toolPresetFile, true)
function load_preset(file, add)
{
try
{
var r = new ActionReference();
r.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID( "toolPreset" ) );
r.putEnumerated( charIDToTypeID( "capp" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var d = new ActionDescriptor();
d.putReference( charIDToTypeID( "null" ), r );
d.putPath( charIDToTypeID( "T " ), file );
if (add != undefined) d.putBoolean( stringIDToTypeID( "append" ), add );
executeAction( charIDToTypeID( "setd" ), d, DialogModes.NO );
}
catch(e) { alert(e); }
}
Copy link to clipboard
Copied
Okey so it works. I based on some really old post of someone who said so and then never tried it on my own.
Well if someone needs the same function for CS6 this person can use VARIATION I:
function LAB(v1, v2) {// v1: 'append', 'load'; v2: file path
function sTT(v) {return stringIDToTypeID(v)}
(ref1 = new ActionReference()).putProperty(sTT('property'), sTT('brush'))
ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));
(dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)
dsc1.putPath(sTT('to'), new File(v2)), dsc1.putBoolean(sTT(v1), true)
executeAction(sTT('set'), dsc1, DialogModes.NO)
}
LAB('load', path + '/Presets/Brushes/Square Brushes.abr') // example
Btw I found that there is no need to use interchangeably 'load' and 'append' values.
You simply can use 'append' only and then use true for appending, while false for loading in VARIATION II:
function LAB(v1, v2) {// v1: true, false; v2: file path
function sTT(v) {return stringIDToTypeID(v)}
(ref1 = new ActionReference()).putProperty(sTT('property'), sTT('brush'))
ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));
(dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)
dsc1.putPath(sTT('to'), new File(v2)), dsc1.putBoolean(sTT('append'), v1)
executeAction(sTT('set'), dsc1, DialogModes.NO)
}
LAB(false, path + '/Presets/Brushes/Square Brushes.abr') // example
This is VARIATION III combaining 'append', 'load', true and false values:
function LAB(v1, v2) {// v1: true, false, 'append', 'load' ; v2: file path
function sTT(v) {return stringIDToTypeID(v)}
(ref1 = new ActionReference()).putProperty(sTT('property'), sTT('brush'))
ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));
(dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)
dsc1.putPath(sTT('to'), new File(v2)), dsc1.putBoolean
(sTT((s = isNaN(v1)) ? v1 : 'append'), s ? true : v1)
executeAction(sTT('set'), dsc1, DialogModes.NO)
}
// you can use either 'load' or false:
LAB('load', path + '/Presets/Brushes/Square Brushes.abr')
// what is equivalent to:
LAB(false, path + '/Presets/Brushes/Square Brushes.abr')
// you can use either 'append' or true
LAB('append', path + '/Presets/Brushes/Square Brushes.abr')
// what is equivalent to:
LAB(true, path + '/Presets/Brushes/Square Brushes.abr')
VARIATION IV expanded of saving possibility (take into consideration that I had to implement removing existing burshes file from Brushes folder if you'd like to save some with the name of that existing file). It's because when abr file with same name exists in Brushes folder it can't be overwritten without security saving dialog. I made workaround that it doesn't pop up, so exactly same when there wasn't a file with current brushes name in Brushes folder.
function LAB(v1, v2) {// v1: null, true, false, 'append', 'load' ; v2: file path
function sTT(v) {return stringIDToTypeID(v)}
(ref1 = new ActionReference()).putProperty(sTT('property'), sTT('brush'))
ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));
(dsc1 = new ActionDescriptor()).putReference(sTT((q = v1 != null) ? 'null' : 'to' ), ref1)
dsc1.putPath(sTT(q ? 'to' :'null'), fle = File(v2)), q ? dsc1.putBoolean
(sTT((s = isNaN(v1)) ? v1 : 'append'), s ? true : v1) : fle.remove()
executeAction(sTT('set'), dsc1, DialogModes.NO)
}
LAB(null, path + '/Presets/Brushes/Square Brushes.abr')
VARIATION V letting you reset current Brushes to default or append default brushes to current ones.
Script knows that you want to reset brushes if second value isn't instered to LAB() function caller.
Besides it works like with loading / replacing brushes, so you can use 'append' / true or 'load' / false
function LAB(v1, v2) {// v1: null, true, false, 'append', 'load' ; v2: file path, null
function sTT(v) {return stringIDToTypeID(v)}
(ref1 = new ActionReference()).putProperty(sTT('property'), sTT('brush'))
ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));
(dsc1 = new ActionDescriptor()).putReference(sTT((q = v1 != null) ? 'null' : 'to' ), ref1)
if (v2) dsc1.putPath(sTT(q ? 'to' :'null'), fle = File(v2)); q ? dsc1.putBoolean
(sTT((s = isNaN(v1)) ? v1 : 'append'), s ? true : v1) : fle.remove()
executeAction(sTT(v2 ? 'set' : 'reset'), dsc1, DialogModes.NO)
}
LAB('load')
NOTE:
when you LOAD brushes by script it's the same you choose REPLACE item in Photoshop
when you APPEND brushes by script it's the same you choose LOAD item in Photoshop
VERSION 5 is final one! Now you can use one function to load, replace, save or reset brushes,
where 'append' can be replaced with true value, while 'load' with false value. So like in reseting.
Copy link to clipboard
Copied
Yes, this is great!
Copy link to clipboard
Copied
Here is how I did it in PhotoshopCC 2018:
Edit > Presets > Preset Manager
Choose Tools as Preset Type:
In the Pop up box, DO NOT ‘Import as Brushes’. Click on ‘Load as Tools’ instead:
Your .tpl file will show up in the list of the Preset Manager box, which is still open.
Say “Done”, and you are done.