Function to Restore Previously Selected Layers

Community Expert ,
Aug 24, 2022 Aug 24, 2022

Copy link to clipboard

Copied

I may have the following layers selected before running some script code that loops over the selected layers:

 

layers.png

 

After running the script, the last layer processed by the loop is selected.

 

It would be nice to return the layer selection back to its original state. Bonus points if this also worked with top level layer sets and the nested contents of layer sets!

 

I am looking for the layer equivalent of:

 

// Save the current active channels
var savedChannelState = app.activeDocument.activeChannels;

// Do stuff...

// Restore the saved active channels
app.activeDocument.activeChannels = savedChannelState;

 

Does anybody have a function for this?

TOPICS
Actions and scripting

Views

97

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 24, 2022 Aug 24, 2022

Copy link to clipboard

Copied

Data about selected layers is stored in the document descriptor. In recent versions, there are three lists for this task: targetLayersIDs, targetLayersIndexes, and targetLayers.

targetLayers is a list of indexes, it historically appeared first. Its advantage is compatibility with older versions of Photoshop. The main drawback is that the indexing of layers in this list always starts from zero, but if it is necessary to re-select layers, only the Background layer can have an index of zero (that is, when using this list, we need to additionally determine whether there is a background layer in the document and set the index offset accordingly ). targetLayersIDs - a list that appeared later, it contains a list of identifiers for the selected layers. I try to always use it, except when I need to ensure compatibility with unsupported versions of Photoshop. targetLayersIndexes also came later, it duplicates the older targetLayers.

That is, we use either:

 

s2t = stringIDToTypeID;
(r = new ActionReference()).putProperty(s2t('property'), s2t('targetLayers'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var selectedLayersList = executeActionGet(r).getList(s2t('targetLayers'));

 

or:

 

s2t = stringIDToTypeID;
(r = new ActionReference()).putProperty(s2t('property'), s2t('targetLayersIDs'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var selectedLayersList = executeActionGet(r).getList(s2t('targetLayersIDs'));

 

Accordingly, as a result, we get either an ActionList with a list of indexes, or with a list of identifiers.

 

ActionList is essentially an array. Before continuing, it makes sense to check if there are elements in it:

 

if (selectedLayersList.count) {}

 

If count is not equal to zero, then the list of selected layers is written to the variable - in fact, this is exactly what we need.

To re-select the layers after the end of processing, using the ScriptListener we get the select command code for one layer (I remove everything unnecessary):

 

var r = new ActionReference()
    r.putIndex(s2t('layer'), index);
    d = new ActionDescriptor()
    d.putReference(s2t('target'), r);
    executeAction(s2t('select'), d, DialogModes.NO)

 

It is clear from the code that we are talking about indexes here, i.e. with a few additions, we can use it with targetLayers or targetLayersIndexes. To move forward, let's prepare our indexes for work: we need to determine whether the document has a background layer or not. If it is, then ok, we are satisfied with the resulting indexing, if not, then we need to add one to each index. This can be done in two ways: compatible with older versions of Photoshop:

 

var offset = 0;
try { activeDocument.backgroundLayer } catch (e) { offset = 1 }

 

or more using the newer document property hasBackgroundLayer:

 

(r = new ActionReference()).putProperty(s2t('property'), s2t('hasBackgroundLayer'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var offset = Number(!executeActionGet(r).getBoolean(s2t('hasBackgroundLayer')));

 

that is, to get the actual value of each index from the list, we need to do something like this in a loop (selectedLayersList contains not just a list of indexes, but an ActionReference list with indexes, that is, we need to make a little effort to get to the value we need):

 

for (var i = 0; i < selectedLayersList.count; i++) {
    var index = selectedLayersList.getReference(i).getIndex(s2t('layer')) + offset
}

 

Now it's the turn to work directly with the re-selection of the layers. Here we have several scenarios. We can use the selection modifier addToSelection (which can be seen in the scriptListener output when more than one layer is selected):

 

d.putEnumerated(s2t('selectionModifier'), s2t('selectionModifierType'), s2t('addToSelection'))

 

and simply execute the select command in a loop (with this approach, there is one peculiarity - we must reset the current set of selected layers so that addToSelection does not supplement it, but starts from scratch):

 

(r = new ActionReference()).putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
(d = new ActionDescriptor()).putReference(s2t('null'), r);
executeAction(s2t('selectNoLayers'), d, DialogModes.NO);

for (var i = 0; i < selectedLayersList.count; i++) {
    var r = new ActionReference()
    r.putIndex(s2t('layer'), selectedLayersList.getReference(i).getIndex(s2t('layer')) + offset);
    d = new ActionDescriptor()
    d.putEnumerated(s2t('selectionModifier'), s2t('selectionModifierType'), s2t('addToSelection'));
    d.putReference(s2t('target'), r);
    executeAction(s2t('select'), d, DialogModes.NO)
}

 

It looks cumbersome (and also slow). There is another approach: instead of executing the select command for a separate index each time, we can place all the ActionReference indexes we have at once and the select command will be executed in one action (in this case, we do not need to deselect other layers, nor use the modifier addToSelection

 

var r = new ActionReference();
for (var i = 0; i < selectedLayersList.count; i++) {
    r.putIndex(s2t('layer'), selectedLayersList.getReference(i).getIndex(s2t('layer')) + offset);
}
d = new ActionDescriptor();
d.putReference(s2t('target'), r);
executeAction(s2t('select'), d, DialogModes.NO)

 

Accordingly, if we work not with a list of indexes, but with identifiers targetLayersIDs, then the code of the maintaining command changes as follows:

 

var r = new ActionReference();
for (var i = 0; i < selectedLayersList.count; i++) {
    r.putIdentifier(s2t('layer'), selectedLayersList.getReference(i).getIdentifier(s2t('layer')));
}
d = new ActionDescriptor();
d.putReference(s2t('target'), r);
executeAction(s2t('select'), d, DialogModes.NO);

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 25, 2022 Aug 25, 2022

Copy link to clipboard

Copied

LATEST

Wow, thanks @jazz-y – that will take a bit of time to digest... Looks like I bit off more than I can chew!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines