How would you get the working (active) layer from an embedded script?
Moderators: Víctor Paredes, Belgarath, slowtiger
How would you get the working (active) layer from an embedded script?
Hi, this may sound like a silly question at first sight at least (and luckily it finally turn to be indeed a silly question), but... Do you think there is a reliable way to get the currently active/working layer in palette from a layer script embedded into another layer anywhere in project? The problem I'm facing is that when used from an embedded script, moho.layer (which is what you'd use for this goal e. g. from a tool/menu script) ALWAYS return the script hosting layer no matter which layer(s) is/are selected in palette, so I don't see how I can trust on it for this purpose.
Besides that, there are at least a couple of functions that I thought could help; for example, I've been trying to use this: moho.document:GetSelectedLayer(0) but, besides it sometimes returns nil randomly I don't know why, it only returns the main working layer as long there is only one layer selected or it is the bottom one of a multi selection.
The other candidate I thought is MohoLayer:SecondarySelection(), but as stayed there, it only says if the layer in question is selected or not, not giving any clue about if it is the working (active) one or any other under a possible multi-selection scenario...
So I'm not finding the way to really can do it, but OTOH it's one of those so basic things that I hope I'm simply missing something or it is in front of me and for some reason I'm overlooking it... In any case, since four eyes see more than two, thanks in advance for any input on the right direction if possible!
Besides that, there are at least a couple of functions that I thought could help; for example, I've been trying to use this: moho.document:GetSelectedLayer(0) but, besides it sometimes returns nil randomly I don't know why, it only returns the main working layer as long there is only one layer selected or it is the bottom one of a multi selection.
The other candidate I thought is MohoLayer:SecondarySelection(), but as stayed there, it only says if the layer in question is selected or not, not giving any clue about if it is the working (active) one or any other under a possible multi-selection scenario...
So I'm not finding the way to really can do it, but OTOH it's one of those so basic things that I hope I'm simply missing something or it is in front of me and for some reason I'm overlooking it... In any case, since four eyes see more than two, thanks in advance for any input on the right direction if possible!
...
Re: How would you get the working (active) layer from an embedded script?
Well, that assuming MohoDoc:ClearSecondarySelection(group) doesn't end up complicating things too much if selected layers are mixed in root or inside/outside of a group, etc. In the absence of anything else for now, I'll start to experiment with this, but I still really hope there is a less convoluted way to get it that for some reason I'm not seeing, or at least something that doesn't imply go deselecting and reselecting layers on the fly while other indirectly involved processes well could be somehow affected.
...
- synthsin75
- Posts: 10266
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: How would you get the working (active) layer from an embedded script?
Usually this is done by finding a layer by another means, like layer name, suffix, tag, etc.. If you know where it is in relation to the embedded layer, that can help.
But all you need is anything that returns a MohoLayer object. In many cases, you'll need to search the whole document: https://mohoscripting.com/snippets/1
But all you need is anything that returns a MohoLayer object. In many cases, you'll need to search the whole document: https://mohoscripting.com/snippets/1
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Re: How would you get the working (active) layer from an embedded script?
Hi and thanks, Wes!
But in this case it could be any layer along the whole project and I just need to know which is the working/active no matter how many of them are selected and in base of no other parameter... so I'm afraid, in the end, I'm kinda screwed?
About parsing all the layers, I've thought on it, but I can't figure out yet what could be the "trigger" for, once the loop get the working layer, return it *unequivocally* in base of... well, in base of something I still can't figure out (it's like I got looped
).
I'm still experimenting with what I commented about deselecting/reselecting, but for some reason I'm not getting results yet... This is where I am right now anyway:
It's just quick/dirty testing and it's late here so maybe I'm, again, overlooking something, but for some reason "workingLayer = doc:GetSelectedLayer(0)" is still giving me the bottom layer of a multi-selection instead what I expected it would give me after clearing secondary selection. It may be just a matter of force some kind of update in-between or something, but I still don't see why it should be necessary here, although I hope some more testing end up throwing some light around it...
But in this case it could be any layer along the whole project and I just need to know which is the working/active no matter how many of them are selected and in base of no other parameter... so I'm afraid, in the end, I'm kinda screwed?
About parsing all the layers, I've thought on it, but I can't figure out yet what could be the "trigger" for, once the loop get the working layer, return it *unequivocally* in base of... well, in base of something I still can't figure out (it's like I got looped

I'm still experimenting with what I commented about deselecting/reselecting, but for some reason I'm not getting results yet... This is where I am right now anyway:
Code: Select all
function LayerScript(moho)
local doc = moho.document
local scriptLayer = moho.layer
local workingLayer = doc:GetSelectedLayer(0)
local selCount = doc:CountSelectedLayers()
local selLayers = {}
if selCount > 1 then
for i = 0, selCount - 1 do
local layer = doc:GetSelectedLayer(i)
table.insert(selLayers, layer)
end
doc:ClearSecondarySelection()
workingLayer = doc:GetSelectedLayer(0) --print(workingLayer:Name())
for i = 1, #selLayers do
local layer = selLayers[i]
layer:SetSecondarySelection(true)
end
end
print(workingLayer:Name())
end
It's just quick/dirty testing and it's late here so maybe I'm, again, overlooking something, but for some reason "workingLayer = doc:GetSelectedLayer(0)" is still giving me the bottom layer of a multi-selection instead what I expected it would give me after clearing secondary selection. It may be just a matter of force some kind of update in-between or something, but I still don't see why it should be necessary here, although I hope some more testing end up throwing some light around it...
...
Re: How would you get the working (active) layer from an embedded script?
OK, it seems as soon as I insert something like "doc:CountSelectedLayers()" in-between "doc:ClearSecondarySelection()" and "workingLayer = doc:GetSelectedLayer(0)" I start getting some results, results that I'll have to stress and see, but at least it's something...
It seems it was indeed an internal update requirement for whatever reason. Or maybe the GetSelectedLayer() method is somehow buggy and that's why it sometimes returns nil randomly and for no reason (thing that I'll still have to figure out how to solve if I want it to be really reliable, BTW).
Again, I didn't expect having to resort to something like this for a so primary necessity as is to know which one is the working layer... but if you agree there is really no easy way to do it in this embedded script cases, at least I can continue working without feeling so stupid as I was feeling before, which is also something
Code: Select all
function LayerScript(moho)
local doc = moho.document
local scriptLayer = moho.layer
local workingLayer = doc:GetSelectedLayer(0)
local selCount = doc:CountSelectedLayers()
local selLayers = {}
if selCount > 1 then
for i = 0, selCount - 1 do --storing current multi-selection
local layer = doc:GetSelectedLayer(i)
table.insert(selLayers, layer)
end
doc:ClearSecondarySelection() --clearing current multi-selection
doc:CountSelectedLayers() --THIS SEEMS TO MAKE IT WORK FOR WHAEVER REASON...
workingLayer = doc:GetSelectedLayer(0) --getting the working layer now that it's the only one selected
for i = 1, #selLayers do --restoring the previous multi-selection
local layer = selLayers[i]
layer:SetSecondarySelection(true)
end
end
print(workingLayer:Name())
end
It seems it was indeed an internal update requirement for whatever reason. Or maybe the GetSelectedLayer() method is somehow buggy and that's why it sometimes returns nil randomly and for no reason (thing that I'll still have to figure out how to solve if I want it to be really reliable, BTW).
Again, I didn't expect having to resort to something like this for a so primary necessity as is to know which one is the working layer... but if you agree there is really no easy way to do it in this embedded script cases, at least I can continue working without feeling so stupid as I was feeling before, which is also something

...
- synthsin75
- Posts: 10266
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: How would you get the working (active) layer from an embedded script?
I forgot that you said you needed to find the selected layer. If it wasn't the primary layer of multiple selected, it would be easy.
I always expect SecondarySelection to only be true for selected layers that aren't the active layer.
Seems like you're on the right path.
I always expect SecondarySelection to only be true for selected layers that aren't the active layer.
Seems like you're on the right path.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Re: How would you get the working (active) layer from an embedded script?
Yeah, that would be SO desirable... It would make everything easy peasy in this cases, and indeed (besides the name itself) for the way it's officially used in "lm_randompointcolors.lua":synthsin75 wrote: ↑Tue Feb 21, 2023 6:56 am I always expect SecondarySelection to only be true for selected layers that aren't the active layer.
Code: Select all
if (layer:LayerType() == MOHO.LT_VECTOR and (layer:SecondarySelection() or layer == moho.layer)) then
Well, let's see if I can solve now the other problem regarding "doc:GetSelectedLayer(0)" randomly returning nil for no apparent reason (although it seem it happens often upon returning focus to Moho's main window), I'm trying some weird workarounds like e. g. forcing it to found something by means of a while block like this:
Code: Select all
while workLayer == nil do
doc:CountSelectedLayers() --THIS SEEMS TO MAKE IT WORK FOR WHATEVER REASON...
workLayer = doc:GetSelectedLayer(0) --getting the working layer now that it's the only one selected while trying to ensure it's not nil?
workLayerID = doc:LayerAbsoluteID(workLayer)
end
...
- hayasidist
- Posts: 3841
- Joined: Wed Feb 16, 2011 8:12 pm
- Location: Kent, England
Re: How would you get the working (active) layer from an embedded script?
There is something not consistent with "getSelectedLayer(i)" -- the first (i=0) IMO ought always to be the "highlighted" layer in the layer panel. It is not always so, as it seems to depend on the order in which layers are manually selected.
Using this test file, and selecting multiple layers, sometimes by click then shift-click to select a range, sometimes by ctrl-click adding layers to the selection ...
Group
>> multiple child layers
Vector
Vector
Vector with layerscript.
... this layerscript ...
... correctly identifies all the selected layers, but shows the issue.
ofc if there's only one selected layer it works fine.
===
as an aside: I do recall adding a note somewhere in mohoscripting about needing to count layers before using an index but I can't find it right now... I'll update this if /when I do...
Using this test file, and selecting multiple layers, sometimes by click then shift-click to select a range, sometimes by ctrl-click adding layers to the selection ...
Group
>> multiple child layers
Vector
Vector
Vector with layerscript.
... this layerscript ...
Code: Select all
function LayerScript(moho)
local ctSel = moho.document:CountSelectedLayers()
local i, layer
if ctSel > 0 then
for i = 0, ctSel-1 do
layer = moho.document:GetSelectedLayer(i)
print ("selected layer ", i, " ", layer:Name())
end
end
end
ofc if there's only one selected layer it works fine.
===
as an aside: I do recall adding a note somewhere in mohoscripting about needing to count layers before using an index but I can't find it right now... I'll update this if /when I do...
Re: How would you get the working (active) layer from an embedded script?
Hi, Paul, and thank you for taking the time of testing it! It's curious there is a so notorious inconsistency in a method widely used by the official tools, so I'm starting to think the problem could only arise while used by an embedded script, for some reason... Another curious thing about I'm seeing now is "doc:GetSelectedLayer(0)" is returning nil here precisely when there is only one layer selected (and that would explain why official tools don't show up the issue). What I'm starting to think according to my latest tests is that, for some reason, even if there is clearly several layers selected in palette, at some script run cycle Moho "thinks" there is only one and that's what could have been messing things... At least that's what it seems at first sight according to this:

And with basically the same code as before, but here it's again for more clarity:
So there it is, the "else" block should never have been run since at that point there was more than one layer selected as can bee seen, but it seems at times "doc:CountSelectedLayers()" returns that only one is selected (or even NO ONE as I recall have seen before, but I still have to test that) and, in this case, caused nothing I tried before above seemed to really take any effect... So, well, knowing that I'm going to continue testing and see...
EDIT: Effectively, at the point the script throws the error "doc:CountSelectedLayers()" returns "0" whereas, supposedly, there should be always at least 1 layer selected in Moho all the time, at least in terms of what it's shown by the UI... Well, let's see if from now on the awareness of that somehow easies things!

And with basically the same code as before, but here it's again for more clarity:
Code: Select all
function LayerScript(moho)
local doc = moho.document
local scriptLayer = moho.layer
local workLayer = nil
local workLayerID = nil
local selCount = doc:CountSelectedLayers()
local selLayers = {}
if selCount > 1 then
for i = 0, selCount - 1 do --storing current multi-selection
local layer = doc:GetSelectedLayer(i)
table.insert(selLayers, layer)
end
doc:ClearSecondarySelection() --clearing current multi-selection
--while workLayer == nil do
doc:CountSelectedLayers() --THIS SEEMS TO MAKE IT WORK FOR WHATEVER REASON...
workLayer = doc:GetSelectedLayer(0) --getting the working layer now that it's the only one selected while trying to ensure it's not nil?
workLayerID = doc:LayerAbsoluteID(workLayer)
moho:SetSelLayer(workLayer, true, true) --layer, multiSelect, allowDeselect
--end
for i = 1, #selLayers do --restoring the previous multi-selection
local layer = selLayers[i]
layer:SetSecondarySelection(true)
end
else print("ELSE")
doc:CountSelectedLayers()
workLayer = doc:GetSelectedLayer(0)
workLayerID = doc:LayerAbsoluteID(workLayer)
end
print("Selected: " .. doc:CountSelectedLayers())
print("Working: " .. workLayer:Name())
--print(doc:LayerByAbsoluteID(workLayerID):Name())
end
So there it is, the "else" block should never have been run since at that point there was more than one layer selected as can bee seen, but it seems at times "doc:CountSelectedLayers()" returns that only one is selected (or even NO ONE as I recall have seen before, but I still have to test that) and, in this case, caused nothing I tried before above seemed to really take any effect... So, well, knowing that I'm going to continue testing and see...
EDIT: Effectively, at the point the script throws the error "doc:CountSelectedLayers()" returns "0" whereas, supposedly, there should be always at least 1 layer selected in Moho all the time, at least in terms of what it's shown by the UI... Well, let's see if from now on the awareness of that somehow easies things!
...
Re: How would you get the working (active) layer from an embedded script?
Well, up to this point I think I'm going to try to go forward with what I have for now... The case is at least the following kind of solution:
Seems to continue returning the correct layer even after the "doc:CountSelectedLayers()" failure, as can be seen here:

So I'll try to implement something like this and then go seeing if it gives any problem under more stress or real usage... Of course I don't lose hope about someone finding something I'm not being able to for such a mundane task as is getting the working layer, but if that doesn't happen at least I may continue working with this, hopefully. Well, thanks for helping!
Code: Select all
function LayerScript(moho)
local doc = moho.document
local scriptLayer = moho.layer
local workLayer = nil
local workLayerID = nil
local selCount = doc:CountSelectedLayers()
local selLayers = {}
if selCount > 1 then
for i = 0, selCount - 1 do --storing current multi-selection
local layer = doc:GetSelectedLayer(i)
table.insert(selLayers, layer)
end
doc:ClearSecondarySelection() --clearing current multi-selection
doc:CountSelectedLayers() --THIS DUMMY LINE SEEMS TO MAKE IT WORK FOR WHATEVER REASON...
workLayer = doc:GetSelectedLayer(0) --getting the working layer now that it's the only one selected
workLayerID = doc:LayerAbsoluteID(workLayer)
--moho:SetSelLayer(workLayer, true, true) --layer, multiSelect, allowDeselect
for i = 1, #selLayers do --restoring the previous multi-selection
local layer = selLayers[i]
layer:SetSecondarySelection(true)
end
elseif selCount == 1 then print("ELSEIF :" .. doc:CountSelectedLayers())
workLayer = doc:GetSelectedLayer(0)
workLayerID = doc:LayerAbsoluteID(workLayer)
else print("ELSE :" .. doc:CountSelectedLayers())
--doc:Refresh()
if prevWorkLayer ~= nil then
workLayer = prevWorkLayer
else
return
end
end
--print(doc:LayerByAbsoluteID(workLayerID):Name())
print("Selected: " .. doc:CountSelectedLayers())
print("Working: " .. workLayer:Name())
prevWorkLayer = workLayer
end

So I'll try to implement something like this and then go seeing if it gives any problem under more stress or real usage... Of course I don't lose hope about someone finding something I'm not being able to for such a mundane task as is getting the working layer, but if that doesn't happen at least I may continue working with this, hopefully. Well, thanks for helping!
...
- hayasidist
- Posts: 3841
- Joined: Wed Feb 16, 2011 8:12 pm
- Location: Kent, England
Re: How would you get the working (active) layer from an embedded script?
FWIW, I've managed to send moho into a loop by adding a layer at the top of the list. IOW with your layers, add a new vector layer above group Layer 9 and watch the fun. At some point in its looping, it will throw the "nil value workLayer" error...
Probably worth a bug report ...
Probably worth a bug report ...
Re: How would you get the working (active) layer from an embedded script?
Well, if we start adding layer addition/deletion to the recipe, for my latest experiences on that matter, it doesn't surprise me at all funny things start happen... That's precisely the reason for I wanted to avoid as much as possible having to play too much with layers state only for this, but it seems selecting/deselecting them is actually not causing any problems, fortunately.
What I mean is I'm not certain about if such loop issue you describe is directly related to this or more with the already reported bugs about layers internal management inconsistencies, although it well could be somehow related, of course. In any case, I'll try to report at least the doc:CountSelectedLayers() returning 0 at times issue, because that seems to me like the most certain inconsistency I see around all this and, hopefully, at some point all together help to improve script layers managing reliability in general... I wish!
What I mean is I'm not certain about if such loop issue you describe is directly related to this or more with the already reported bugs about layers internal management inconsistencies, although it well could be somehow related, of course. In any case, I'll try to report at least the doc:CountSelectedLayers() returning 0 at times issue, because that seems to me like the most certain inconsistency I see around all this and, hopefully, at some point all together help to improve script layers managing reliability in general... I wish!
...
- synthsin75
- Posts: 10266
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: How would you get the working (active) layer from an embedded script?
Might be easier to keep a running tally of selected layers. If the number increases, the layer newly added to the selection is the active layer. If the number decreases, either there is only one layer selected or one's been deselected. If the latter, the new active layer is either the one below the deselected layer (in layer hierarchy) or the lowest, if the lowest was deselected.
I would just have the layerscript return whenever CountSelectedLayers returns zero.
I would just have the layerscript return whenever CountSelectedLayers returns zero.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Re: How would you get the working (active) layer from an embedded script?
Indeed, the idea is this piece of code only be run if the number of selected layers change, at first simply with performance reasons in mind but now with more reason for also reducing at minimum the possibilities of getting false CountSelectedLayers() returns, so I could consider to extend the principle up to the point of what you suggest, Wes. It kind of hurt a little to try to take into account all the possibilities but, as you point, they are really not so much... The only exception I'm seeing for this to be totally workable is upon switching top working layer to bottom working layer (and vice-versa) with the shift key pressed under a multi-selection scenario, since the number of selected layers doesn't change in that case (or at least not visually in UI, I may have to test it by a script to see if something changes from there by chance susceptible to be caught).
For now I think I'm going to continue using this method because I feel like advance a little, but as soon as it present some problem or limitation (as I'm afraid will happen at some point as usually end happening with patches), I think I might start to consider that other way around, so thank you for pointing it out!
For now I think I'm going to continue using this method because I feel like advance a little, but as soon as it present some problem or limitation (as I'm afraid will happen at some point as usually end happening with patches), I think I might start to consider that other way around, so thank you for pointing it out!
...
- synthsin75
- Posts: 10266
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: How would you get the working (active) layer from an embedded script?
Damn, I missed that one. I wonder how often anyone does that though.Ramón López wrote: ↑Wed Feb 22, 2023 1:42 am The only exception I'm seeing for this to be totally workable is upon switching top working layer to bottom working layer (and vice-versa) with the shift key pressed under a multi-selection scenario, since the number of selected layers doesn't change in that case (or at least not visually in UI, I may have to test it by a script to see if something changes from there by chance susceptible to be caught).
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/