Rename and sort FBF childlayers by timeline appearance
Posted: Thu Apr 08, 2021 8:33 pm
I've been experimenting with some tweaks in an attempt to try and make FBF more useable. One of them is this script that renames each child of a FBF layer to its first appearance, for example if Layer 1 is has a switchkey on frame 5, 6 and 20, it will be renamed "Frame_00005". Unused frames will be named "Unused". After that it sorts the frames by name. Which kind of works, but when you try and select an old frame to re-use via the switch-dropdown, the order is all wrong, because it's actually the 'animated' layer order of the 'layer order channel'... So it's ordered correctly in the layer panel, but not in the right click switch menu (or ctrl+alt+righ click menu).
Not sure it's possible to re-order the layers in another way. If anyone can figure out a different trick that'd be nice. Without the menu being alphabetically ordered the script isn't as useful as I hoped it would be.
Edit: Thanks for the help Wes, it works. This code below is the updated script.
Edit: Re-used frames now get their own color so you can distinguish them. (red = blank frame) (plain = regular drawing used once) (other color = re-used drawings)
Here it is:
I wanted to add the script after a custom "new fbf frame" shortcut so it would run every time you create a new frame:
Not sure it's possible to re-order the layers in another way. If anyone can figure out a different trick that'd be nice. Without the menu being alphabetically ordered the script isn't as useful as I hoped it would be.
Edit: Thanks for the help Wes, it works. This code below is the updated script.
Edit: Re-used frames now get their own color so you can distinguish them. (red = blank frame) (plain = regular drawing used once) (other color = re-used drawings)
Here it is:
Code: Select all
-- ************************************************************************************
-- Rename and sort sublayers of a FBF switchlayer to "Frame 1" etc. to match their first timeline appearance
-- ************************************************************************************
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************
ScriptName = "LK_RenameFBFLayers"
-- **************************************************
-- General information about this script
-- **************************************************
LK_RenameFBFLayers = {}
function LK_RenameFBFLayers:Name()
return "Rename FBF-frames"
end
function LK_RenameFBFLayers:Version()
return "0"
end
function LK_RenameFBFLayers:Description()
return "Rename and sort sublayers of a FBF switchlayer to 'Frame 1' etc. to match their time."
end
function LK_RenameFBFLayers:Creator()
return "Lukas Krepel, Frame Order"
end
function LK_RenameFBFLayers:UILabel()
return "Rename FBF-frames"
end
-- **************************************************
-- The guts of this script
-- **************************************************
function LK_RenameFBFLayers:IsEnabled(moho)
if moho.layer:LayerType() ~= MOHO.LT_SWITCH then
return false
else
local switchLayer = moho:LayerAsSwitch(moho.layer)
if not switchLayer:IsFBFLayer() then
return false
end
end
return true
end
function LK_RenameFBFLayers:Run(moho)
moho.document:PrepUndo(moho.layer)
moho.document:SetDirty()
LK_RenameFBFLayers:Rename(moho)
end
function LK_RenameFBFLayers:Rename(moho)
local switchLayer = moho:LayerAsSwitch(moho.layer)
local channel = switchLayer:SwitchValues() -- 10106 = CHANNEL_SWITCH
local endKey = channel:Duration()
local thisKey = 0
local keyCount = channel:CountKeys()
local keysFound = 0
local frameNum = endKey
local layers = {}
for i = switchLayer:CountLayers()-1, 0, -1 do
layer = switchLayer:Layer(i)
table.insert(layers, layer)
end
for i = 1, #layers do
local layer = layers[i]
layer:SetName("tempname "..i)
end
local frameLayers = {}
local alreadyColored = {}
local reuseColors = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }
local col = 1
while keysFound < keyCount do
keysFound = 1 + keysFound
thisKey = channel:GetClosestKeyID(frameNum)
keyFrameNum = channel:GetKeyWhen(thisKey)
local leadingZeros = string.format("%05d", keyFrameNum)
local newName = "Frame_"..leadingZeros
local keyValue = switchLayer:GetValue(keyFrameNum)
frameNum = keyFrameNum - 1
for i = 1, #layers do
local layer = layers[i]
local layerName = layer:Name()
if layerName == keyValue then
if table.contains(frameLayers, layer) then
if not table.contains(alreadyColored, layer) then
local color = reuseColors[col]
col = col + 1
layer:SetLabelColor(color) -- * From table For re-used frames.
table.insert(alreadyColored, layer)
layer:SetName(newName.." *")
end
else
layer:SetName(newName)
layer:SetLabelColor(0) -- * 0 = Plain -- For regular frames.
end
local mesh = moho:LayerAsVector(layer):Mesh()
if mesh:CountPoints() == 0 then
layer:SetLabelColor(1) -- * 2 = orange -- For empty frames.
if table.contains(frameLayers, layer) then
--layer:SetLabelColor(1) -- * 1 = red -- For re-used empty frame.
end
end
table.insert(frameLayers, layer)
end
end
end
local unusedCount = 0
local blankReusedCount = 1
for i = 1, #layers do
local layer = layers[i]
if layer:LabelColor() == 1 then
if blankReusedCount == 1 then
layer:SetName("Blank")
else
layer:SetName("Blank "..blankReusedCount)
end
blankReusedCount = blankReusedCount + 1
end
if not table.contains(frameLayers, layer) then
unusedCount = unusedCount + 1
layer:SetName("Unused_"..unusedCount)
layer:SetLabelColor(1) -- * 1 = red
end
end
self:SortByName(moho)
end
-- **************************************************
-- Sort layers by name
-- **************************************************
function LK_RenameFBFLayers:SortByName(moho)
-- * Create table
local thisLayer = moho:LayerAsGroup(moho.layer)
thisLayer:EnableLayerOrdering(false)
local order, layer, layerName = {}
for i = thisLayer:CountLayers()-1, 0, -1 do
layer = thisLayer:Layer(i)
layerName = layer:Name()
table.insert(order, {layer, layerName})
end
-- * Sort table alphabetically:
table.sort(order,
function(a,b)
return (a[2]<b[2])
end)
-- * Sort layer order:
if #order > 1 then
for i = 1, #order-1 do
local moveLayer = order[i+1][1]
local behindLayer = order[i][1]
moho:PlaceLayerBehindAnother(moveLayer, behindLayer)
end
end
-- *
moho.layer:UpdateCurFrame()
moho.view:DrawMe()
end
-- **************************************************
-- Check whether a table contains an element
-- **************************************************
function table.contains(table, element)
if table ~= nil then
for _, value in pairs(table) do
if value == element then
return true
end
end
end
return false
end
Code: Select all
moho.document:PrepUndo(moho.layer)
moho.document:SetDirty()
local switchLayer = moho:LayerAsSwitch(moho.layer)
local currentLayerName = switchLayer:GetValue(moho.frame)
local layers = {}
for i = switchLayer:CountLayers()-1, 0, -1 do
layer = switchLayer:Layer(i)
table.insert(layers, layer)
end
local encounter = false
for i = 1, #layers do
local layer = layers[i]
local layerName = layer:Name()
--print (layerName.." == "..currentLayerName)
if layerName == currentLayerName then
encounter = true
moho:SetSelLayer(layer, false, false)
break
end
end
if not encounter then
print ("error... "..currentLayerName)
return
end
moho:CreateNewLayer(LT_VECTOR, false)
local channel = switchLayer:SwitchValues() -- 10106 = CHANNEL_SWITCH
channel.value:Set(moho.layer:Name())
channel:StoreValue()
moho:SetSelLayer(switchLayer, false, false)
LK_RenameFBFLayers:Rename(moho)
moho:UpdateUI()