Image
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "LK_LayerFinder"

-- **************************************************
-- General information about this script
-- **************************************************

LK_LayerFinder = {}

function LK_LayerFinder:Name()
	return 'Layer Finder'
end

function LK_LayerFinder:Version()
	return '0.2'
end

function LK_LayerFinder:UILabel()
	return 'Layer Finder'
end

function LK_LayerFinder:Creator()
	return 'Lukas Krepel'
end

function LK_LayerFinder:Description(mode)
	if self.mode == 1 then
		return "Select keyed layers."
	elseif self.mode == 2 then
		return "Select bone + keyed child-layers."
	elseif self.mode == 3 then
		return "Select layers tagged 'Rig'."
	end
end

function LK_LayerFinder:ColorizeIcon()
	return true
end

-- **************************************************
-- Is Relevant / Is Enabled
-- **************************************************

function LK_LayerFinder:IsRelevant(moho)
	if FO_Utilities:MohoVersion(moho) < 14 then
		return false
	end
	if MohoMode ~= nil then
		if MohoMode.vanilla then
			return false
		end
	end
	return true
end

LK_LayerFinder.dialog = nil

LK_LayerFinder.buttonCount = 10



-- **************************************************
-- LK_LayerFinderDialog
-- **************************************************

local LK_LayerFinderDialog = {}

LK_LayerFinder.modes = { "Keys", "Bone", "Rig" }
LK_LayerFinder.mode = 1
LK_LayerFinder.ignoreHidden = true
LK_LayerFinder.pageCount = 1
LK_LayerFinder.currentPage = 1
LK_LayerFinder.layers = {}

LK_LayerFinderDialog.SELECT_PREVIOUS_MODE	= MOHO.MSG_BASE + 0
LK_LayerFinderDialog.SELECT_NEXT_MODE		= MOHO.MSG_BASE + 1
LK_LayerFinderDialog.PAGE_DOWN				= MOHO.MSG_BASE + 2
LK_LayerFinderDialog.PAGE_UP				= MOHO.MSG_BASE + 3
LK_LayerFinderDialog.SELECT_MODE			= MOHO.MSG_BASE + 10	-- * 10 t/m 99
LK_LayerFinderDialog.SELECT_LAYER			= MOHO.MSG_BASE + 100	-- * 100 t/m 199
LK_LayerFinderDialog.SELECT_LAYER_ALT		= MOHO.MSG_BASE + 200	-- * 200 t/m 299

function LK_LayerFinderDialog:new()
	local d = LM.GUI.SimpleDialog('Layer Finder', LK_LayerFinderDialog)
	local l = d:GetLayout()
	local width = 180
	l:PushV(LM.GUI.ALIGN_LEFT, 0)
	l:PushH(LM.GUI.ALIGN_LEFT, 1)
	-- * Mode dropdown:
	d.modeLabel = LM.GUI.StaticText("Mode:")
	l:AddChild(d.modeLabel)

	d.modeDropdown_popup = LM.GUI.PopupMenu(100, false)
	l:AddChild(d.modeDropdown_popup)
	-- *
	l:PushH(LM.GUI.ALIGN_CENTER, 0)
	d.prevModeButton = LM.GUI.ImageButton("ScriptResources/FO_icons/arrow_left", "Previous mode", false, self.SELECT_PREVIOUS_MODE, true)
	l:AddChild(d.prevModeButton, LM.GUI.ALIGN_LEFT, 0)
	d.nextModeButton = LM.GUI.ImageButton("ScriptResources/FO_icons/arrow_right", "Next mode", false, self.SELECT_NEXT_MODE, true)
	l:AddChild(d.nextModeButton, LM.GUI.ALIGN_LEFT, 0)
	l:Pop() -- * H
	l:Pop() -- * H
	-- *
	d.descriptionText = LM.GUI.DynamicText('', width)
	l:AddChild(d.descriptionText, LM.GUI.ALIGN_LEFT, 0)
	d.staticText = LM.GUI.StaticText("Hold <alt> to select multiple layers.")
	l:AddChild(d.staticText, LM.GUI.ALIGN_LEFT, 0)
	l:Pop() -- * V
	l:PushV(LM.GUI.ALIGN_RIGHT, 0) -- * to include pagecount txt.
	-- * Buttons to select layers:

	l:PushV(LM.GUI.ALIGN_LEFT, 0)
	d.buttons = {}
	for i = 1, LK_LayerFinder.buttonCount do
		if i == 1 or i == LK_LayerFinder.buttonCount then
			l:PushH(LM.GUI.ALIGN_LEFT, 0) -- * Horizontal for page up/down buttons.
		end
		local button = LM.GUI.Button('room for a big loooong name', d.SELECT_LAYER + i)
		button:SetAlternateMessage(d.SELECT_LAYER_ALT + i)
		l:AddChild(button, LM.GUI.ALIGN_LEFT, 0)
		table.insert(d.buttons, button)
		if i == 1 then
			d.pageUpButton = LM.GUI.ImageButton("ScriptResources/FO_icons/dialUp", "Page up.", false, self.PAGE_UP, true)
			l:AddChild(d.pageUpButton, LM.GUI.ALIGN_TOP)
		end
		if i == LK_LayerFinder.buttonCount then
			d.pageDownButton = LM.GUI.ImageButton("ScriptResources/FO_icons/dialDown", "Page down.", false, self.PAGE_DOWN, true)
			l:AddChild(d.pageDownButton, LM.GUI.ALIGN_BOTTOM)
		end
		if i == 1 or i == LK_LayerFinder.buttonCount then
			l:Pop() -- * Horizontal for page up/down buttons.
		end
	end
	l:Pop() -- * Vertical layerselectbuttons
	-- *
	d.pageText = LM.GUI.DynamicText('', 80)
	-- l:AddChild(d.pageText, LM.GUI.ALIGN_RIGHT, 0)
	-- *
	d.infoText = LM.GUI.DynamicText('', width)
	l:AddChild(d.infoText, LM.GUI.ALIGN_LEFT, 0)
	l:Pop() -- * V
	return d
end

function LK_LayerFinderDialog:HandleMessage(msg)
	local helper = MOHO.ScriptInterfaceHelper:new_local()
	local moho = helper:MohoObject()
	if msg == self.SELECT_NEXT_MODE then
		LK_LayerFinder.mode = LK_LayerFinder.mode + 1
		if LK_LayerFinder.mode > #LK_LayerFinder.modes then
			LK_LayerFinder.mode = 1
		end
	elseif msg == self.SELECT_PREVIOUS_MODE then
		LK_LayerFinder.mode = LK_LayerFinder.mode - 1
		if LK_LayerFinder.mode < 1 then
			LK_LayerFinder.mode = #LK_LayerFinder.modes
		end
	elseif msg == self.PAGE_DOWN then
		LK_LayerFinder.currentPage = LK_LayerFinder.currentPage + 1
		if LK_LayerFinder.currentPage > LK_LayerFinder.pageCount then
			LK_LayerFinder.currentPage = 1
		end
	elseif msg == self.PAGE_UP then
		LK_LayerFinder.currentPage = LK_LayerFinder.currentPage - 1
		if LK_LayerFinder.currentPage < 1 then
			LK_LayerFinder.currentPage = LK_LayerFinder.pageCount
		end
	elseif msg < self.SELECT_LAYER then
		local i = msg - self.SELECT_MODE
		LK_LayerFinder.mode = i
	elseif msg >= self.SELECT_LAYER then
		local i = msg - self.SELECT_LAYER
		altKey = false
		if i >= 100 then
			i = i - 100
			altKey = true
		end
		local layer = LK_LayerFinder.layers[i + (LK_LayerFinder.currentPage-1)*LK_LayerFinder.buttonCount]
		if layer == nil then
			print ("uh oh")
			return
		end
		local multiSelect = altKey
		moho:SetSelLayer(layer, multiSelect, false)
		FO_Utilities:CollapseGroups(moho)
		moho:ShowLayerInLayersPalette(layer)
		if LK_LayerFinder.mode == 2 or LK_LayerFinder.mode == 3 then -- * 2 = Bone / 3 = Rig
			FO_Utilities:SecondarySelectKeyedChildLayers(moho, layer)
		end
	end
	moho:UpdateUI()
	helper:delete()
end

function LK_LayerFinderDialog:OnOK()
	LK_LayerFinder.dialog = nil
end


function LK_LayerFinder:WhatLayers(moho)
	local layers = {}
	local mode = self.mode
	if mode == 3 then
		layers = FO_Utilities:ListLayersWithTag(FO_Utilities.rigTag, moho)
	elseif mode == 2 then
		layers = FO_Utilities:ListLayersOfType(MOHO.LT_BONE, moho)
	elseif mode == 1 then
		local allLayers = FO_Utilities:AllLayers(moho)
		for i = 1, #allLayers do
			local layer = allLayers[i]
			if FO_Utilities:LayerIsAnimated(moho, layer) then
				table.insert(layers, layer)
			end
		end
	end
	-- *
	if self.ignoreHidden then
		for i = 1, #layers do
			local layer = layers[i]
			if layer == nil then
				break
			end
			if not layer:IsVisible() then
				table.removeElement(layers, layer)
				i = i - 1
			end
		end
	end
	-- *
	table.reverse(layers)
	return layers
end


function LK_LayerFinderUpdateDialog(moho)
	if LK_LayerFinder.dialog ~= nil then
		LK_LayerFinder:UpdateWidgets()
	end
end

table.insert(MOHO.UpdateTable, LK_LayerFinderUpdateDialog)


function LK_LayerFinder:UpdateWidgets()
	for i = 1, #self.dialog.buttons do
		local button = self.dialog.buttons[i]
		button:Enable(false)
		button:SetLabel("", false)
		button:SetToolTip("")
	end
	-- * Create moho object:
	local helper = MOHO.ScriptInterfaceHelper:new_local()
	local moho = helper:MohoObject()
	-- *
	self.layers = self:WhatLayers(moho)
	self.dialog.infoText:SetValue(math.floor(moho.document:CountSelectedLayers()).." selected layers.")
	self.pageCount = 1
	self.pageCount = math.ceil(#self.layers/self.buttonCount)
	if self.pageCount == 0 then
		self.pageCount = 1
	end
	if self.currentPage > self.pageCount then
	self.currentPage = self.pageCount
	end
	self.dialog.pageText:SetValue(("Page "..self.currentPage.."/"..self.pageCount))
	for i = 1, self.buttonCount do
		local button = self.dialog.buttons[i]
		local layer = self.layers[i + (self.currentPage-1)*self.buttonCount]	
		if layer ~= nil then
			button:SetToolTip(FO_Utilities:LayerStructure(layer))
			local buttonLabel = layer:Name()
			if layer == moho.layer then
				buttonLabel = "→ "..buttonLabel.." ←"
				button:SetValue(true) -- * Doesn't show it unfortunately...
			elseif layer:SecondarySelection() then
				buttonLabel = "・ "..buttonLabel.." ・"
				button:SetValue(true) -- * Doesn't show it unfortunately...
			else
				button:SetValue(false) -- * Doesn't show it unfortunately...
			end
			button:SetLabel(buttonLabel, false)
			button:Redraw()
			button:Enable(true)
		end
	end
	--
	self.dialog.descriptionText:SetValue(self:Description(self.mode))
	-- * Update mode dropdown:
	self.dialog.modeDropdown_menu = LM.GUI.Menu(self.modes[self.mode])
	for i = 1, #LK_LayerFinder.modes do
		self.dialog.modeDropdown_menu:AddItem(self.modes[i], 0, self.dialog.SELECT_MODE+i)
		self.dialog.modeDropdown_menu:SetChecked(self.dialog.SELECT_MODE+i, i==self.mode)
	end
	self.dialog.modeDropdown_popup:SetMenu(self.dialog.modeDropdown_menu)
	self.dialog.modeDropdown_popup:Redraw()
	-- * Update Page up/down buttons:
	self.dialog.pageUpButton:Enable(self.currentPage ~= 1)
	self.dialog.pageDownButton:Enable(self.currentPage ~= self.pageCount)
	-- * Delete moho object:
	helper:delete()
end

-- **************************************************
-- The guts of this script
-- **************************************************
function LK_LayerFinder:Run(moho)
	if self.dialog == nil then
		self.dialog = LK_LayerFinderDialog:new(moho)
		-- * Crash fix by Rai Lopez https://www.lostmarble.com/forum/viewtopic.php?p=214189#p214189
		self.dlogBypass = LK_LayerFinderDialog:new(moho) self.dlogBypass = nil
		-- * End of fix
		self.dialog:DoModeless()
	end
end

Icon
Layer Finder
Listed

Author: Lukas View Script
Script type: Button/Menu

Uploaded: Sep 12 2023, 09:36

Last modified: Oct 10 2023, 06:16

Quickly find and select layers with keys and rig layers
This is basically an extra layers-panel to quickly find and select layers with keys and rig layers without needing to filter the original layer panel. You can use both at the same time.

Only works with Moho version 14.0 and up.

Please contact me in the discord channel or at the Lost Marble forums if you're encountering any bugs.
Image

Installation Options:

This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 492