Try this code. Script uses Photoshop events and launches itself when notifications appear, so be sure to save it to disk before running.
On first run, the script will set up event tracking for painting to canvas and switching presets. As you paint on the canvas by any tool from object 'trackTools', Photoshop will call a script to remember the tool's name and brush options. After you switch the preset, the script will receive current tool data and try to find the previously saved brush parameters, if it succeeds, it will update the tool settings and return the previous parameters.
When you restart Photoshop, the brush settings remembered by the script are reset. To disable event tracking, simply run the script again.
#target photoshop
var t2s = typeIDToStringID,
s2t = stringIDToTypeID,
evt = null,
tgt = null;
var trackTools = {
spotHealingBrushTool: true,
magicStampTool: true,
paintbrushTool: true,
pencilTool: true,
colorReplacementBrushTool: true,
wetBrushTool: true,
cloneStampTool: true,
patternStampTool: true,
historyBrushTool: true,
artBrushTool: true,
eraserTool: true,
backgroundEraserTool: true,
blurTool: true,
sharpenTool: true,
smudgeTool: true,
dodgeTool: true,
burnInTool: true,
saturationTool: true
};
try { tgt = arguments[0], evt = t2s(arguments[1]) } catch (e) { };
try {
if (evt) {
switch (evt) {
case 'toolModalStateChanged':
if (t2s(tgt.getEnumerationValue(s2t('kind'))) == 'paint') {
if (tool = getCurrentToolOptions())
if (trackTools[tool.toolName]) app.putCustomOptions(tool.toolName, tool.brush, false)
}
break;
case 'select':
if (tool = getCurrentToolOptions()) {
try { var tracked = app.getCustomOptions(tool.toolName) } catch (e) { }
if (tracked) {
tool.brush.putUnitDouble(s2t('diameter'), s2t('pixelsUnit'), tracked.getUnitDoubleValue(s2t('diameter')));
tool.brush.putUnitDouble(s2t('hardness'), s2t('percentUnit'), tracked.getUnitDoubleValue(s2t('hardness')));
tool.options.putObject(s2t('brush'), s2t('computedBrush'), tool.brush);
(r = new ActionReference()).putClass(s2t(tool.toolName));
(d = new ActionDescriptor()).putReference(s2t('target'), r);
d.putObject(s2t('to'), s2t('target'), tool.options);
executeAction(s2t('set'), d, DialogModes.NO);
}
}
break;
}
} else {
var ntf = new Notifiers,
status = ntf.checkNotifier();
if (status) ntf.delNotifier(); else ntf.addNotifier();
alert('Brush tracking ' + (status ? 'disabled' : 'enabled') + '!\nRun "' + decodeURI(File($.fileName).name) + '" again to ' + (status ? 'enable' : 'disable') + ' it')
}
} catch (e) { }
function getCurrentToolOptions() {
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('tool'));
r.putEnumerated(s2t('application'), s2t('ordinal'), s2t('targetEnum'));
var d = executeActionGet(r),
o = d.getObjectValue(s2t('currentToolOptions'));
if (o.hasKey(s2t('brush'))) {
return {
toolName: t2s(d.getEnumerationType(s2t('tool'))),
options: o,
brush: o.getObjectValue(s2t('brush'))
}
} else return null
}
function Notifiers() {
this.addNotifier = function () {
app.notifiersEnabled = true
var handlerFile = File($.fileName)
app.notifiers.add('toolModalStateChanged', handlerFile)
app.notifiers.add('select', handlerFile, 'toolPreset')
}
this.delNotifier = function () {
var handlerFile = File($.fileName).name,
len = app.notifiers.length;
for (var i = 0; i < len; i++) {
if (app.notifiers[i].eventFile.name == handlerFile) {
app.notifiers[i].remove(); i--; len--
}
}
}
this.checkNotifier = function () {
var handlerFile = File($.fileName).name,
len = app.notifiers.length;
for (var i = 0; i < len; i++) {
if (app.notifiers[i].eventFile.name == handlerFile) return true
}
return false
}
}
P.S. I tried to set the brush parameters directly, but this caused unwanted effects, in particular, the scattering option always resetted. Couldn't quickly fix this problem, so the script updates whole tool settings.