How do I create a new moho file and copy a layer to it via script?

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

Moderators: Víctor Paredes, Belgarath, slowtiger

User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

I'm stuck and am not sure if it's an API or skill limitation... So here we are.

I want to create a script that copies the current layer to a new empty document and saves that document in a specific folder. Close the new document and continue working on the original file.

After moho:FileNew() is it possible to edit the newly created moho document and save and close it? To return to the initial document? I've tried numerous things but failed...

Here's what I got currently:

Code: Select all

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

ScriptName = "LK_ExportLayerToTodoFolder"

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

LK_ExportLayerToTodoFolder = {}

function LK_ExportLayerToTodoFolder:Name()
	return 'Export Layer to Todo-folder'
end

function LK_ExportLayerToTodoFolder:Version()
	return '1.0'
end

function LK_ExportLayerToTodoFolder:UILabel()
	return 'Export Layer to Todo-folder'
end

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

function LK_ExportLayerToTodoFolder:Description()
	return 'Export selected layer(s) to Todo-folder'
end


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

function LK_ExportLayerToTodoFolder:IsRelevant(moho)
	return true
end

function LK_ExportLayerToTodoFolder:IsEnabled(moho)
	return true
end

-- **************************************************
-- LK_ExportLayerToTodoFolderDialog
-- **************************************************

local LK_ExportLayerToTodoFolderDialog = {}

LK_ExportLayerToTodoFolderDialog.DUMMY = MOHO.MSG_BASE
LK_ExportLayerToTodoFolderDialog.BROWSE_BUTTON = MOHO.MSG_BASE + 1

function LK_ExportLayerToTodoFolderDialog:new(moho)
	local d = LM.GUI.SimpleDialog('Export Layer to Todo-folder', LK_ExportLayerToTodoFolderDialog)
	local l = d:GetLayout()
	-- *
	l:PushH()
		d.browseButton = LM.GUI.Button("Todo Folder", d.BROWSE_BUTTON)
		l:AddChild(d.browseButton)
		d.todoFolderPathText = LM.GUI.DynamicText('Room for a big loooooooooooooooooooooooooooong path', 0)
		l:AddChild(d.todoFolderPathText, LM.GUI.ALIGN_LEFT, 0)
	l:Pop()
	-- *
	l:PushH()
		l:PushV()
			l:AddChild(LM.GUI.StaticText("Filename:"), LM.GUI.ALIGN_RIGHT, 0)
			l:AddPadding(10)
			l:AddChild(LM.GUI.StaticText("Notes:"), LM.GUI.ALIGN_RIGHT, 0)
		l:Pop()
		l:PushV()
			local fileName = moho.layer:Name()..".moho"
			d.filenameTextBox = LM.GUI.TextControl(200, fileName, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.filenameTextBox, LM.GUI.ALIGN_LEFT, 0)
			l:AddPadding(10)
			LK_ExportLayerToTodoFolder.note1 = "Origin file: "..moho.document:Path()
			LK_ExportLayerToTodoFolder.note2 = "Layer path: "..FO_Utilities:LayerStructure(moho.layer)
			LK_ExportLayerToTodoFolder.note3 = ""
			d.noteTextBox = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note1, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.noteTextBox, LM.GUI.ALIGN_LEFT, 0)
			d.noteTextBox2 = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note2, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.noteTextBox2, LM.GUI.ALIGN_LEFT, 0)
			d.noteTextBox3 = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note3, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.noteTextBox3, LM.GUI.ALIGN_LEFT, 0)
		l:Pop()
	l:Pop()
	return d
end

function LK_ExportLayerToTodoFolderDialog:UpdateWidgets(moho)
	self.todoFolderPathText:SetValue(LK_ExportLayerToTodoFolder.todoFolderPath)
end

-- **************************************************
-- The guts of this script
-- **************************************************

LK_ExportLayerToTodoFolder.note1 = ""
LK_ExportLayerToTodoFolder.note2 = ""
LK_ExportLayerToTodoFolder.note3 = ""
LK_ExportLayerToTodoFolder.todoFolderPath = "/Volumes/megagamma_data/Club Baboo/Rigs/_TODO/"

function LK_ExportLayerToTodoFolder:Run(moho)
	local dlog = LK_ExportLayerToTodoFolderDialog:new(moho)
	if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
		return
	end
	local sourcePath = moho.document:Path()
	local exportLayer = moho.layer
	local targetPath = self.todoFolderPath..exportLayer:Name()..".moho"
	moho:FileNew()
	moho:FileSaveAs(targetPath)
	moho:FileOpen(targetPath)
	moho:PlaceLayerBehindAnother(exportLayer, moho.document:Layer(0))
	moho:DeleteLayer(moho.document:Layer(0))
	--
	local notes = { self.note1, self.note2, self.note3 }
	local i = #notes
	while i > 0 do
		local note = notes[i]
		if note ~= "" then
			local noteLayer = moho:CreateNewLayer(MOHO.LT_NOTE, false)
			noteLayer = moho:LayerAsNote(noteLayer)
			noteLayer:SetNoteText(note)
			noteLayer:SetName(note)
			local vec3 = LM.Vector3:new_local()
			vec3.y = -0.1 * (i-1)
			noteLayer.fTranslation:SetValue(0, vec3)
		end
		i = i - 1
	end
	moho:FileSave()
	moho:FileClose()
	moho:FileOpen(sourcePath)
end
(The todo-folder-path is currently hardcoded, so you need to change that when trying it)
(It needs FO_Utilities)

(I tried a different method by saving the whole document as a duplicate and deleting 100s of layers except the selected one I needed, saving it as a new file and re-opening the initial file, but opening takes a LONG time because it's a huge file dependant on huge images from a server. So that's not an option)
User avatar
hayasidist
Posts: 3525
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: How do I create a new moho file and copy a layer to it via script?

Post by hayasidist »

hope this is useful ... it is mostly guesswork ... take a look at LM_scatterbrush.Lua

That does "local doc = moho:LoadDocument(docPath)" calls and then uses vectors from the layers in one of the loaded documents.

SO .... (supposition here 'cos I've never actually tried this) ...

assuming FileNew() creates an empty moho doc (and not just an empty "text" doc)

it would be Load (rather than Open) and get a new MohoDoc class for that, and then put the desired layer into that, the save and close it???
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

hayasidist wrote: Wed Nov 29, 2023 4:57 pm hope this is useful ... it is mostly guesswork ... take a look at LM_scatterbrush.Lua
That does "local doc = moho:LoadDocument(docPath)" calls and then uses vectors from the layers in one of the loaded documents.
Thanks. I have imported from other MohoDoc's successfully before! But only ever when loading information from another MohoDoc into the current moho.document MohoDoc.
hayasidist wrote: Wed Nov 29, 2023 4:57 pm SO .... (supposition here 'cos I've never actually tried this) ...

assuming FileNew() creates an empty moho doc (and not just an empty "text" doc)

it would be Load (rather than Open) and get a new MohoDoc class for that, and then put the desired layer into that, the save and close it???
The problem is (I think...), you can't really save another MohoDoc, even if you Load it. As moho:FileSave() and moho:FileSaveAs(path) don't take a MohoDoc argument and will always assume you want to save the current moho.document.

I hope I'm wrong about this though :|
User avatar
hayasidist
Posts: 3525
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: How do I create a new moho file and copy a layer to it via script?

Post by hayasidist »

Lukas wrote: Wed Nov 29, 2023 7:37 pm The problem is (I think...), you can't really save another MohoDoc, even if you Load it. As moho:FileSave() and moho:FileSaveAs(path) don't take a MohoDoc argument and will always assume you want to save the current moho.document.
? can you set moho.document to be the one you want and then moho:FileSave()??? after all, you can write to fields such as moho.frame
User avatar
synthsin75
Posts: 9977
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by synthsin75 »

Since there's no API for copying layers across documents, I *think* you'd need to do this:
1. create your new document and save it, like you're doing (there's no need to open this file, as it should already be the current document)
2. use something like loadDoc = moho:LoadDocument(path) to load the original file, even though it's opened on another tab
3. find the desired original layer and *maybe* moho:DuplicateLayer(layer, byReference), defining the layer by loadDoc:Layer(n)
4. save and close the new document
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

synthsin75 wrote: Thu Nov 30, 2023 1:12 am Since there's no API for copying layers across documents, I *think* you'd need to do this:
1. create your new document and save it, like you're doing (there's no need to open this file, as it should already be the current document)
2. use something like loadDoc = moho:LoadDocument(path) to load the original file, even though it's opened on another tab
3. find the desired original layer and *maybe* moho:DuplicateLayer(layer, byReference), defining the layer by loadDoc:Layer(n)
4. save and close the new document
I'll give this a try! Thanks :)
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

...I don't think it works? I can't seem to edit the new document at all. For example:

Code: Select all

moho:FileNew()
moho:CreateNewLayer(MOHO.LT_NOTE, false)
print(moho.document:Name())
...creates a node layer in the 'old' document, not in the new one. It also prints the name of the 'old' document, not the new Untitled project. I can't duplicate (or move) a layer into the new doc.

It's weird, because moho:SaveFileAs() does actually save the new doc, which seems like a strange exception to the rule, it always just the empty untouched new file. :/
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Rai López »

Lukas wrote: Thu Nov 30, 2023 11:37 am ...It also prints the name of the 'old' document, not the new Untitled project...
🤔 That kind of reminds me to a problem I faced some days ago with FileOpen, but the same well may apply? In my case, and accordingly to my notes, the problem had to do with the fact FileOpen function immediately made run, among others, isRelevant/isEnabled functions and then continued running the code after that precise point, turning out I was unnexpetedly/suddenly dealing with the wrong moho object (the one created in such functions and not the one created at the beginning of the function I was, HandleMessage in my case), resulting everything pointed me to a previously open document instead of the new one... Anyway, the way I got to solve it was by simply deleting the current moho object just before calling FileOpen and then create another one right after the call, like this:

Code: Select all

	print("1: " .. moho.document:Name())
	helper:delete()
	moho:FileOpen(doc:Path())
	local helper = MOHO.ScriptInterfaceHelper:new_local() -- 20231120-0545: FileOpen immediately calls isRelevant/isEnabled & Dialog_Update, messing up (I think) current MohoObject, so a new one ensures openning document is targeted instead a previously opened one.
	local moho = helper:MohoObject()
	print("2: " .. moho.document:Name())

And, after that, everything started to work as expected. It might sound kind of obvious now, but it was kind of a madness get to figure out... Well, not sure if it will be the same (I hope!) in your case, but it well may worth a try, so (even if it's finally only FTR) there it is. Cheers.
...
User avatar
synthsin75
Posts: 9977
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by synthsin75 »

It looks like this may be a somewhat similar case as modeless dialogs before the helper object, where the initial document state persists throughout the entirety of the function run.

In this case, the moho object passed to the run function cannot be changed until the function is initiated/run again. Even if you use a helper object, it's just an instance of the moho object passed to the run function. So I have no idea how you'd get a new document's moho object within the same run that created the document.

The only immediate solution I can think of is to make it a two-step process.
1. Run the script to store the desired layer ID to a global variable and make the new document and save it
2. Run the script again, initiating it with the new document already open (and its moho object), to LoadDocument from the original. Then you should be able to duplicate the the layer in the new document, save, and close it.


After some testing:

I take that back. You can do it running the script only once, like this:
1. Select desired layer
2. Ctrl+N
3. Run the script

First, you have to find a way to store the selected layer in a global variable. This is what I came up with:

Code: Select all

function LK_ExportLayerToTodoFolder:IsEnabled(moho)
	if (moho.document:Path() == self.lastdoc and self.lastLayer ~= moho.layer) then
		self.layerID = moho.document:LayerID(moho.layer)
		self.docPath = moho.document:Path()
	end
	self.lastLayer = moho.layer
	self.lastdoc = moho.document:Path()
	return true
end
Then Ctrl+N to create a new document.
Then run the script once. (Note: If you play around in the new document before running the script, my method of storing the selected layer may not be terribly robust.)

Code: Select all

function LK_ExportLayerToTodoFolder:Run(moho)
	if (self.docPath) then
		local origdoc = moho:LoadDocument(self.docPath)
		local name = origdoc:Layer(self.layerID):Name()
		local newlayer = moho:DuplicateLayer(origdoc:Layer(self.layerID), false)
		newlayer:SetName(name)
		local targetPath = self.todoFolderPath..name..".moho"
		moho:DestroyDocument(origdoc)
		moho:FileSaveAs(targetPath)
		moho:FileClose()
	end
end
This loads the original doc in the new environment, duplicates the selected layer with the original layer name, saves the new doc with the selected layer name, and closed the new doc returning you to your original doc.

Not terribly straight forward, but seems to work.
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

Thanks guys!

I didn't think about using the moho-helper-object! Nice. I did try to fix it that way for a bit, but didn't get far. Might not work in this case? I do feel you should be able to update moho.document after creating new files... I hope we can get some API updates, generating moho files is kind of an obvious thing to want to script in productions. (Until now we've only been generating JSON .anme files with an edited version of one of Mike's old Photoshop scripts from way back).

I implemented Wes' suggestion (thanks!), but without relying on IsEnabled, as it behaved a bit finicky and unpredictable. So you do have to run the script twice unfortunately. Also had to switch to Layer UUID, as nested layers don't have a LayerID.

Here's my solution if anyone's interested (paths to the destination folder and some document resolution and fps (1080p/25fps) are hardcoded, so change those to your needs):

Code: Select all

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

ScriptName = "LK_ExportLayerToTodoFolder"

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

LK_ExportLayerToTodoFolder = {}

function LK_ExportLayerToTodoFolder:Name()
	return 'Export Layer to Todo-folder'
end

function LK_ExportLayerToTodoFolder:Version()
	return '1.0'
end

function LK_ExportLayerToTodoFolder:UILabel()
	return 'Export Layer to Todo-folder'
end

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

function LK_ExportLayerToTodoFolder:Description()
	return 'Export selected layer(s) to Todo-folder'
end


-- **************************************************
-- Is Relevant / Is Enabled
-- **************************************************
function LK_ExportLayerToTodoFolder:IsRelevant(moho)
	return true
end


function LK_ExportLayerToTodoFolder:IsEnabled(moho)
	return true
end


-- **************************************************
-- LK_ExportLayerToTodoFolderDialog
-- **************************************************

local LK_ExportLayerToTodoFolderDialog = {}


LK_ExportLayerToTodoFolderDialog.DUMMY = MOHO.MSG_BASE
LK_ExportLayerToTodoFolderDialog.BROWSE_BUTTON = MOHO.MSG_BASE + 1


function LK_ExportLayerToTodoFolderDialog:new(moho)
	local d = LM.GUI.SimpleDialog('Export Layer to Todo-folder', LK_ExportLayerToTodoFolderDialog)
	local l = d:GetLayout()
	-- *
	l:PushH()
		d.browseButton = LM.GUI.Button("Todo Folder", d.BROWSE_BUTTON)
		l:AddChild(d.browseButton)
		d.todoFolderPathText = LM.GUI.DynamicText('Room for a big loooooooooooooooooooooooooooong path', 0)
		l:AddChild(d.todoFolderPathText, LM.GUI.ALIGN_LEFT, 0)
	l:Pop()
	-- *
	l:PushH()
		l:PushV()
			l:AddChild(LM.GUI.StaticText("Filename:"), LM.GUI.ALIGN_RIGHT, 0)
			l:AddPadding(10)
			l:AddChild(LM.GUI.StaticText("Notes:"), LM.GUI.ALIGN_RIGHT, 0)
		l:Pop()
		l:PushV()
			LK_ExportLayerToTodoFolder.filename = moho.layer:Name()..".moho"
			d.filenameTextBox = LM.GUI.TextControl(200, LK_ExportLayerToTodoFolder.filename, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.filenameTextBox, LM.GUI.ALIGN_LEFT, 0)
			l:AddPadding(10)
			LK_ExportLayerToTodoFolder.note1 = "Origin file: "..LK_ExportLayerToTodoFolder.sourceDocPath
			LK_ExportLayerToTodoFolder.note2 = "Layer path: "..LK_ExportLayerToTodoFolder.sourceLayerPath
			LK_ExportLayerToTodoFolder.note3 = ""
			d.note1TextBox = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note1, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.note1TextBox, LM.GUI.ALIGN_LEFT, 0)
			d.note2TextBox = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note2, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.note2TextBox, LM.GUI.ALIGN_LEFT, 0)
			d.note3TextBox = LM.GUI.TextControl(300, LK_ExportLayerToTodoFolder.note3, d.DUMMY, LM.GUI.FIELD_TEXT, nil)
			l:AddChild(d.note3TextBox, LM.GUI.ALIGN_LEFT, 0)
		l:Pop()
	l:Pop()
	return d
end


function LK_ExportLayerToTodoFolderDialog:OnOK()
	LK_ExportLayerToTodoFolder.filename = self.filenameTextBox:Value()
	LK_ExportLayerToTodoFolder.note1 = self.note1TextBox:Value()
	LK_ExportLayerToTodoFolder.note2 = self.note2TextBox:Value()
	LK_ExportLayerToTodoFolder.note3 = self.note3TextBox:Value()
end


function LK_ExportLayerToTodoFolderDialog:UpdateWidgets(moho)
	self.todoFolderPathText:SetValue(LK_ExportLayerToTodoFolder.todoFolderPath)
end


-- **************************************************
-- The guts of this script
-- **************************************************


LK_ExportLayerToTodoFolder.layerUUID = ""
LK_ExportLayerToTodoFolder.layerName = ""
LK_ExportLayerToTodoFolder.sourceDocPath = ""
LK_ExportLayerToTodoFolder.sourceLayerPath = ""
LK_ExportLayerToTodoFolder.filename = ""
LK_ExportLayerToTodoFolder.note1 = ""
LK_ExportLayerToTodoFolder.note2 = ""
LK_ExportLayerToTodoFolder.note3 = ""
LK_ExportLayerToTodoFolder.todoFolderPath = "/Volumes/megagamma_data/Club Baboo/Rigs/_TODO/"


function LK_ExportLayerToTodoFolder:Run(moho)
	if (FO_Utilities:getOS() == "unix") then
		LK_ExportLayerToTodoFolder.todoFolderPath = "/Volumes/megagamma_data/Club Baboo/Rigs/_TODO/"
	else
		LK_ExportLayerToTodoFolder.todoFolderPath = "Y:\\Club Baboo\\Rigs\\_TODO\\"
	end

	if moho.document:Path() ~= "" then
		self.sourceDocPath = moho.document:Path()
		self.layerUUID = moho.layer:UUID()
		self.layerName = moho.layer:Name()
		self.sourceLayerPath = FO_Utilities:LayerStructure(moho.layer)
		local dlog = LK_ExportLayerToTodoFolderDialog:new(moho)
		if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
			return
		end
		FO_Utilities:Alert("i", "Hit Ctrl+N to create a new empty document and run this script again.", "File: "..self.sourceDocPath, "Layer: "..FO_Utilities:LayerStructure(moho.layer))
	else
		--
		moho.document:SetShape(1920, 1080)
		moho.document:SetFps(25)
		local deleteLayer = moho.document:Layer(0)
		-- Add notes:
		local notes = { self.note1, self.note2, self.note3 }
		local i = #notes
		while i > 0 do
			local note = notes[i]
			if note ~= "" then
				local noteLayer = moho:CreateNewLayer(MOHO.LT_NOTE, false)
				noteLayer = moho:LayerAsNote(noteLayer)
				noteLayer:SetNoteText(note)
				noteLayer:SetName(note)
				noteLayer:SetImmuneToCamera(true)
				noteLayer:SetLabelColor(1)
				local vec3 = LM.Vector3:new_local()
				vec3.x = -1.66
				vec3.y = 1 + (-0.1 * i)
				noteLayer.fTranslation:SetValue(0, vec3)
				moho:PlaceLayerBehindAnother(noteLayer, deleteLayer)
			end
			i = i - 1
		end
		local sourceDoc = moho:LoadDocument(self.sourceDocPath)
		FO_Utilities:MatchStyles(sourceDoc, moho.document)
		local layers = FO_Utilities:AllLayers(moho, sourceDoc)
		local sourceLayer = nil
		for i = 1, #layers do
			local layer = layers[i]
			if layer:UUID() == self.layerUUID then
				sourceLayer = layer
				break
			end
		end
		if sourceLayer == nil then
			FO_Utilities:Alert("Can't find layer UUID ("..self.layerUUID..") in moho file: '"..self.sourceDocPath.."'")
			return
		end
		local duplicatedLayer = moho:DuplicateLayer(sourceLayer, false)
		duplicatedLayer:SetName(sourceLayer:Name())
		moho:PlaceLayerBehindAnother(duplicatedLayer, deleteLayer)
		moho:DeleteLayer(deleteLayer)
		if string.match(string.lower(self.filename), "%.moho$") == nil then
			self.filename = self.filename..".moho"
		end
		local filePath = self.todoFolderPath..self.filename
		filePath = self:GenerateNewFilename(moho, filePath)
		moho:FileSaveAs(filePath)
		FO_Utilities:Alert("i", "Saved layer '"..duplicatedLayer:Name().."' to '"..filePath.."'")
		-- FO_Utilities:RevealDirectory(LK_ExportLayerToTodoFolder.todoFolderPath)
	end
end


function LK_ExportLayerToTodoFolder:GenerateNewFilename(moho, original)
	local counter = 1
	local newFilename = original
	local extensionPos = string.find(newFilename, "%.moho$")
	local baseName = newFilename
	if extensionPos then
		baseName = newFilename:sub(1, extensionPos - 1)
	end
	while FO_Utilities:FileExists(moho, newFilename) do
		newFilename = baseName.." "..counter..".moho"
		counter = counter + 1
	end
	return newFilename
end
To use it:

1. Select any layer in a saved(!) project
2. Run the script
3. Fill in the dialog, you can add notes and change the filename if you want (it will never overwrite, so if you export a layer with the same name it will just save them as "Head.moho", "Head 1.moho", "Head 2.moho" etc.
4. Hit Ctrl+N to create a new empty document and run the script a second time (as the popup explains)
5. Close the newly created document, it has already been saved in the 'todo' folder (as the popup explains) (Because moho:FileClose() crashes???)

We use this script to add layers of (for example) new switchlayer hands/mouths that are created on the fly during the animation process to a 'todo' folder, as a reminder to update rigs and implement and tidy them up them later on.
User avatar
SimplSam
Posts: 1048
Joined: Thu Mar 13, 2014 5:09 pm
Location: London, UK
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by SimplSam »

Glad you found a solution, but for what you are trying to achieve overall - would it not be easier to add 'TODO' Tags to the layers and have batch processes that review the project files for the 'TODO' tags etc etc.
Moho 14.1 » Win 11 Pro 64GB » NVIDIA GTX 1080ti 11GB
Moho 14.1 » Mac mini 2012 8GB » macOS 10.15 Catalina
Tube: SimplSam


Sam
User avatar
synthsin75
Posts: 9977
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by synthsin75 »

Lukas wrote: Fri Dec 01, 2023 3:22 pm I didn't think about using the moho-helper-object! Nice. I did try to fix it that way for a bit, but didn't get far. Might not work in this case? I do feel you should be able to update moho.document after creating new files... I hope we can get some API updates, generating moho files is kind of an obvious thing to want to script in productions. (Until now we've only been generating JSON .anme files with an edited version of one of Mike's old Photoshop scripts from way back).

I implemented Wes' suggestion (thanks!), but without relying on IsEnabled, as it behaved a bit finicky and unpredictable. So you do have to run the script twice unfortunately. Also had to switch to Layer UUID, as nested layers don't have a LayerID.
Yeah, I don't think the helper object will work for this.

I should have used LayerAbsoluteID, but UUID works too.

SimplSam wrote: Fri Dec 01, 2023 4:10 pm Glad you found a solution, but for what you are trying to achieve overall - would it not be easier to add 'TODO' Tags to the layers and have batch processes that review the project files for the 'TODO' tags etc etc.
Yeah, I'd probably go that route, instead of running the script twice for each layer.
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by Lukas »

Yeah, that would be a smarter way to go about it if I had to export a lot of different layers from a single moho file to their individual new files, but that's not what we're going to use this for. I do appreciate you guys thinking along though!!!

It's intended for situations where we improve rigs on the fly during the animation process (like adding a hand in a switch or revising the points in a vector). This script will allow the animator to quickly save the layer to a folder without leaving the animation flow too much and without worrying about naming conventions or file location etc.

Then, when the episode is done and we revisit the rigs, we can just go to that specific export folder and go through the files and implement them in the correct way in the source rig files.

I do wish we could do this without Ctrl+N and running the script twice, because the purpose of this script was actually to keep the animator focussed on the shot. Just hit a button and the layer is sent away for later. Removing the hassle was kind of the point, but now it's just different hassle.
User avatar
hayasidist
Posts: 3525
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: How do I create a new moho file and copy a layer to it via script?

Post by hayasidist »

I've been looking at this (albeit behind the curve!). I've come to the conclusion that FileClose() doesn't work as expected and I'd appreciate some other pairs of eyes on this.

Given the requirement is to save a vector layer, I focused on copy/paste. This works right up to the point where FileClose gets called -- whereupon "nothing happens".

Nearly nothing that is. The Lua Console Window seems to close but then re-open with the "done it" diagnostic - leaving the secondary file correctly updated but open.

There's nothing fancy in it to get user input... and

The code is intended to run in my test harness (so, if you want to pick it up and get diagnostics, please change the local HS_Test_harness definitions or add your own "print").

HOLD ON...

OMG It actually works as long as there's no Lua Console window open (or is it when there's no activity on the console when the ScriptInterface object is associated with the "New" file).

OK -- can someone please run this with and without some print diagnostics in it in the two scenarios:

-- print when the ScriptInterface object refers to the original file (expecting the script to work);
-- print when the ScriptInterface object refers to the new file (expecting the script NOT to work -- i.e. it closes and reopens Lua console; does not close new file.)


Code: Select all

HS_writeVec = {}
local thisUUT = "B"

local HS_Test_harness = {}
HS_Test_harness.tracePrint = function () end
HS_Test_harness.diagnosePrint = function () end


function HS_writeVec:Run(moho, view)
	HS_Test_harness:tracePrint (thisUUT,  self:Name(), self:Version())

	local i, j, k, n, p, q, s

	local err
	local mesh 


--
-- **	assume we have an open file with an active vector layer.
--
	local vectorLayer = moho:LayerAsVector(moho.layer)
	if (vectorLayer ~= nil) then
		HS_Test_harness:tracePrint (thisUUT,  "Got vector layer", vectorLayer:Name())
		local mesh = vectorLayer:Mesh()
		mesh:SelectAll()
		moho:Copy(mesh)
		HS_Test_harness:tracePrint (thisUUT,  "Copied Mesh")
	else
		HS_Test_harness:tracePrint (thisUUT,  "no Mesh")
		return
	end
--
-- ** 	assume the source has been saved, but give a useless default if not
--

	p, s = moho.document:Path()

	if #p == 0 then
		p = "noname.moho"
	else
		HS_Test_harness:diagnosePrint (thisUUT,  "source doc", p)
	end
	
	
--
-- ** 	create a trivial name for the (to be) new file by sticking "pp" on the end of the source name
--

	q = string.reverse (p)
	HS_Test_harness:diagnosePrint (thisUUT,  "rev", q)
	q = string.gsub (q, "%.", ".pp" , 1) -- this just sticks a "pp" on the end of the original file name
	p = string.reverse (q)
	HS_Test_harness:diagnosePrint (thisUUT,  "copy doc", p)


--
-- **	open the new file (and confirm that it's unnamed)
--

	local oldDoc = moho.document

	moho:FileNew()
	newDoc = moho.document

	s = moho.document:Path()

	if #s == 0 then
		HS_Test_harness:diagnosePrint (thisUUT,  "new doc not yet named")
	else
		HS_Test_harness:diagnosePrint (thisUUT,  "new doc named", s)
	end

--
-- ** 	assume (but check) it has a vector layer (as is usual in the default new doc), then paste and save [all works as expected]
--
	local vectorLayer = moho:LayerAsVector(moho.layer)
	if (vectorLayer ~= nil) then
		HS_Test_harness:tracePrint (thisUUT,  "Got vector layer", vectorLayer:Name())
		moho:Paste()
		moho:FileSaveAs(p)
	else
		HS_Test_harness:tracePrint (thisUUT,  "no vec in new doc")
	end
	
--
-- **	pause to check the log, then close [Does not work as expected]
--

	LM.Snooze(5000)
	moho:FileClose()
	HS_Test_harness:tracePrint (thisUUT,  "Closed?!") -- >>> output in new Lua console window -- seems that "FileClose" closes the wrong stream??????? 
--										which MIGHT explain Lukas's "Because moho:FileClose() crashes???" if there wasn't an "extra stream" to close????????

end
User avatar
synthsin75
Posts: 9977
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: How do I create a new moho file and copy a layer to it via script?

Post by synthsin75 »

Yeah, when I was testing this, it seemed that any print function would derail the file close.
I think I only saw this when trying to close the new file, but haven't tested any further.
Post Reply