seach through all child layers?

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

Post Reply
User avatar
rylleman
Posts: 750
Joined: Tue Feb 15, 2005 5:22 pm
Location: sweden
Contact:

seach through all child layers?

Post by rylleman »

I only manage to loop through the first level of childs and manually down into those one level at a time by adding "if (currentlayer:IsGroupType()) then"-functions.

How can I search through all sublayers and their subgroups (and sublgroups to those, etc.) no matter how deep they go?
Stan
Posts: 199
Joined: Sun Apr 19, 2009 3:22 pm

Re: seach through all child layers?

Post by Stan »

You need a recursive function (a function that invokes itself).
Here's an example from one of my scripts:

Code: Select all

-- declare a table variable  self.LayersToChange

function SZ_RelativeLineWidth:ScanSelectedLayers(moho)
	for l = 0, moho.document:CountSelectedLayers()-1 do
		local layer = moho.document:GetSelectedLayer(l)
		if moho:LayerAsVector(layer) then
			table.insert(self.LayersToChange, moho.document:LayerAbsoluteID(layer))
		elseif layer:IsGroupType() then
			self:ScanGroup(moho, layer)
		end
	end
end

function SZ_RelativeLineWidth:ScanGroup(moho, group)
	local groupLayer = moho:LayerAsGroup(group)
	for i=0, groupLayer:CountLayers()-1 do
		local layer = group:Layer(i)
		if layer:IsGroupType() then
			self:ScanGroup(moho, layer) -- recursion
		elseif moho:LayerAsVector(layer) then
			table.insert(self.LayersToChange, moho.document:LayerAbsoluteID(layer))
		end
	end
end 

When you call the ScanSelectedLayers, it will scan all selected layers, and call the recursive method ScanGroup for all group layers, if there's any. As the result, the self.LayersToChange variable will contain absolute IDs of all nested vector layers.
________________________________________________________________________
https://mohoscripting.com/ - Unofficial Moho Lua scripting documentation
https://mohoscripts.com/ - The best place to publish and download scripts for Moho
Stan
Posts: 199
Joined: Sun Apr 19, 2009 3:22 pm

Re: seach through all child layers?

Post by Stan »

A more elegant solution would be to create a local recursive function. More info here: https://www.lua.org/pil/6.2.html
________________________________________________________________________
https://mohoscripting.com/ - Unofficial Moho Lua scripting documentation
https://mohoscripts.com/ - The best place to publish and download scripts for Moho
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: seach through all child layers?

Post by synthsin75 »

Stan wrote:You need a recursive function (a function that invokes itself).
Here's an example from one of my scripts:

Code: Select all

-- declare a table variable  self.LayersToChange

function SZ_RelativeLineWidth:ScanSelectedLayers(moho)
	for l = 0, moho.document:CountSelectedLayers()-1 do
		local layer = moho.document:GetSelectedLayer(l)
		if moho:LayerAsVector(layer) then
			table.insert(self.LayersToChange, moho.document:LayerAbsoluteID(layer))
		elseif layer:IsGroupType() then
			self:ScanGroup(moho, layer)
		end
	end
end

function SZ_RelativeLineWidth:ScanGroup(moho, group)
	local groupLayer = moho:LayerAsGroup(group)
	for i=0, groupLayer:CountLayers()-1 do
		local layer = group:Layer(i)
		if layer:IsGroupType() then
			self:ScanGroup(moho, layer) -- recursion
		elseif moho:LayerAsVector(layer) then
			table.insert(self.LayersToChange, moho.document:LayerAbsoluteID(layer))
		end
	end
end 

When you call the ScanSelectedLayers, it will scan all selected layers, and call the recursive method ScanGroup for all group layers, if there's any. As the result, the self.LayersToChange variable will contain absolute IDs of all nested vector layers.

Stan, does a function recursively calling itself work better now days? I remember when I first tried that, it seemed to eat up a lot of memory for large projects (scanning the whole document). That is the simplest (and most readable) method, but I usually do this:

Code: Select all

	-- **************************************************
	-- Recursive search
	-- **************************************************
	local layers = {}
	local stack = {}
	local sp = 0
	for i=0, moho.document:CountLayers()-1 do
		local layer = moho.document:Layer(i)
		table.insert(layers, layer)
		local group = nil
		local layerID = 0
		while true do
			if (layer:IsGroupType()) then
				table.insert(stack, {group, layerID -1})
				sp = sp+1
				group = moho:LayerAsGroup(layer)
				layerID = group:CountLayers()
			end
			if (layerID > 0) then
				layerID = layerID -1
				layer = group:Layer--[[ByDepth]](layerID)
				table.insert(layers, layer)
			else
				layerID = -1
				while (sp > 0) do
					group, layerID = stack[sp][1], stack[sp][2]
					table.remove(stack)
					sp = sp -1
					if (layerID >= 0) then
						layer = group:Layer--[[ByDepth]](layerID)
						table.insert(layers, layer)
						break
					end
				end
			end
			if (layerID < 0) then
				break
			end
		end
	end
	-- **************************************************
Based on Fazek's method, from the old meshinstance script.
Stan
Posts: 199
Joined: Sun Apr 19, 2009 3:22 pm

Re: seach through all child layers?

Post by Stan »

I didn't have any issues using recursion. Well, maybe my projects weren't large enough... And, of course, I didn't use recursion inside frequently called methods like MouseMove or LayerScript. Anyway, I'm glad you have another solution that I wasn't aware of. Thank you, and many thanks to the genius of Fazek.
I love to have such technical discussions, we should do this more often!
________________________________________________________________________
https://mohoscripting.com/ - Unofficial Moho Lua scripting documentation
https://mohoscripts.com/ - The best place to publish and download scripts for Moho
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: seach through all child layers?

Post by synthsin75 »

Yeah, sometimes I think the scripting forum could stand to have sub-forums. Where general scripting snippets like these have no logical place in the scripting documentation, it would be nice to have a forum dedicated to collecting them. Sticky topics would get too numerous, and a single long thread might be hard to search.

Every once in awhile we have these discussions on the AF, but usually about problems no one has solved yet.
User avatar
hayasidist
Posts: 3493
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: seach through all child layers?

Post by hayasidist »

recursion seems to be fine for me too

- this scans the global table and creates an html file: http://www.kelleytown.com/forum/animato ... IC_ID=1431 (improvement on the "print globals" built-in script) - tested/validated against Moho 12

- this bakes all layer / bone etc motion into point motion, and set all the layer translations, rotations etc to 0 (and scale to 1)
http://www.kelleytown.com/forum/animato ... hichpage=2 **NOT verified for Moho12** This does the "all child layers" scan as per the OP.
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: seach through all child layers?

Post by synthsin75 »

It was probably all the way back in v7 or 8 that a self-calling function would cause a memory leak, since the internal calls would never seem to get garbage collection done. Maybe that's been fixed in a newer version of Lua since then. I still suspect the routine I use may be less resource heavy.
GaryC
Posts: 53
Joined: Tue Feb 03, 2015 1:02 pm

Re: seach through all child layers?

Post by GaryC »

Recursive calls on whole documents can definitely get heavy for me using layer scripts on large files, it works a lot better if you're not storing the layers anywhere just execute the code you need to when you find layers. And generally be mindful of how much a recursive function ends up needing to run. Limit scope and save time where you can.
Post Reply