Building GUIs With Fusion's UI Manager

User avatar
Midgardsormr
Fusionista
Posts: 936
Joined: Wed Nov 26, 2014 8:04 pm
Location: Los Angeles, CA, USA
Been thanked: 26 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#136

Post by Midgardsormr » Tue May 22, 2018 3:52 pm

After yet another read-through of this amazingly helpful thread, I stumbled over a few unaddressed questions that I now know the answers to:

SirEdric wrote: is there any chance to set the height of (e.g.) a button to a fixed value?

I have a logo header image in a UI I'm working on right now, a base64 image rendered as HTML into a TextEdit widget, and I wanted to be sure that the window would never be so small as to create scroll bars in that header:

  1.             ui:VGroup{
  2.                 ID = 'header',
  3.                 ui:TextEdit{ ID = 'museLogo', ReadOnly = true, FixedSize = { width, 130 }, Alignment = { AlignHCenter = true, AlignTop = true, }, HTML = html, },
  4.                
  5.             },

width is given by the function call that creates the window—it's the overall width of the window upon creation. The only trouble I have at the moment is that it creates a fixed width for the entire window, although the height is still liquid. The FixedSize attribute is valid for any UIWidget.

Midgardsormr wrote:Andrew, you mentioned early in the thread that you would return to the topic of Trees to describe how to set up disclosure controls for displaying sub items. Have you any code samples or hints for that yet?

When creating a typical entry to a tree, it is done by first creating the item with item = tree:NewItem(). Then the columns for that item can be set, and the item is added to the tree with tree:AddTopLevelItem(item).

To add a child to that item, you create it just like any other item: child = tree:NewItem(). Then run item:AddChild(child) to add it as a child of the top level item. The disclosure arrow will appear automatically in the first column for the top-level item.

If you want the tree to be expanded by default, set item.Expanded = true.


  1. --Assume a tree item with ID 'Tree' is present in the UI Manager window 'win'
  2. itm = win:GetItems()
  3.  
  4. -- Add a row entry
  5. itRow = itm.Tree:NewItem()
  6. itRow.Text[0] = 'parent'
  7. itm.Tree:AddTopLevelItem(itRow)
  8.  
  9. -- Add child
  10. itChild = itm.Tree:NewItem()
  11. itChild.Text[0] = 'child'
  12. itRow:AddChild(itChild)
Midgardsormr wrote:ItemIsDropEnabled? ItemIsEditable? I wants them! But I can't figure out what to do with this information. If I could get a drop-down menu from a Tree, I'd be extremely happy. Likewise if I could allow typing in a Tree's field.

The method UITreeItem:SetFlags() allows you to change these properties. The trick, though, is that you apparently have to set all of the available flags for it to work, even if you only want to change one of them. The flags are these:

ItemIsSelectable = true
ItemIsDropEnabled = true
ItemIsTristate = false
ItemNeverHasChildren = false
ItemIsDragEnabled = true
ItemIsEditable = false
ItemIsUserCheckable = true
ItemIsEnabled = true

To make a field editable:
itm:SetFlags( { ItemIsSelectable = true, ItemIsDropEnabled = true, ItemIsTristate = false, ItemNeverHasChildren = false, ItemIsDragEnabled = true, ItemIsEditable = true, ItemIsUserCheckable = true, ItemIsEnabled = true } )

I haven't yet experimented with it to learn what is the most appropriate event to use for interacting with it. I would guess ItemChanged.

I still don't think it's possible to insert a combo box into a tree field, unfortunately.

SirEdric wrote:Is there something like RadioButtons (or Multibutton, as it is called in FuScript) in the new GUIManager?

Not directly, but you can simulate it with a loop across a group of buttons. Assume you have a group of buttons with the IDs Button1, Button2, Button3. They're all checkable, and you want to allow only one button to be checked at a time. You'll need three functions, one for each button. An example function:

Code: Select all

function mainWindow.On.Button1.Clicked(ev) 
	for key, value in pairs(mainWindowItems) do
		i = string.len(value.ID)
		name = string.sub(value.ID, 1, i-1)			-- Strips the last character from the control's name
		if name == 'Button' and ev.who ~= value.ID 	-- It's one of the buttons, but not the one that was clicked
			value.Checked == false
		end
	end  
end

Notice that the test condition is generic so the same code can be used in all three functions without having to keep track of which one it was. This also lets you dynamically create the Clicked functions with a loop.

Tags:

User avatar
Midgardsormr
Fusionista
Posts: 936
Joined: Wed Nov 26, 2014 8:04 pm
Location: Los Angeles, CA, USA
Been thanked: 26 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#137

Post by Midgardsormr » Tue May 22, 2018 4:08 pm

Midgardsormr wrote:
Mon May 21, 2018 2:24 pm
Instead of hiding the existing window and making a new one for each step, I decided to look into what would need to be done to remove items and add new ones.

I ran into an issue with this process. If you try to add more than one new item with AddChild(), they'll all get stacked on top of one another. The solution is to call window:RecalcLayout() after adding the new items.

User avatar
AndrewHazelden
Fusionator
Posts: 1219
Joined: Fri Apr 03, 2015 3:20 pm
Location: West Dover, Nova Scotia, Canada
Been thanked: 11 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#138

Post by AndrewHazelden » Tue May 22, 2018 5:06 pm

Dynamic GUI Layouts

Midgardsormr wrote:
Tue May 22, 2018 4:08 pm
I ran into an issue with this process. If you try to add more than one new item with AddChild(), they'll all get stacked on top of one another. The solution is to call window:RecalcLayout() after adding the new items.
Sounds like you've been programming up a storm with new UI Manager GUIs. Is it mostly translating IUP based Lua scripts, or new development work?

The Atomizer GUI update that is in Reactor v2.0 uses the itm.root:AddChild() approach for the creation of the HTML code formatting button bar. Then the HTML output code for each of the button's tasks came from a shared table called buttonTbl = {} for all controls in the formatting bar. It was fun to explore.

The ui:Buttons were generated on the fly in the GUI and ui:Icon image paths are loaded too from a Lua table. This code was something I put together for the first time for this updated Atomizer project and it hasn't really evolved much from the first attempt I made. You can find Atomizer as a built-in item that is is in the Reactor > Tools > Atomizer menu. That Lua script can be opened as a text file at Reactor:/System/UI/Atomizer.lua

Atomizer GUI.png

Loading Images via HTML in UI Manager

As a tip about adding JPG images to ui:TextEdit fields using the HTML mode:

You don't always have to use base64 encoding inline for the resources if more then 1 file is allowed for the whole tool. You could store all the images external to the script in a folder and then access them using the absolute filepath and the HTML window will render them correctly.

I've fallen in love with the Lua debug functions that Fusion exposes like debug.getinfo(1).source which gives you the filepath where the Lua script was run from. The one catch is if you run the Lua script from Fuscript as inline code from your text editor IDE or do a Console paste in of the code you need to add a fallback path to avoid any unexpected errors.

If images an in a folder next to the Lua script you can use it to work out on the fly the location where everything is stored. It's very freeing compared to my earlier approach of forcing a fixed installation location on the users somewhere like Scripts:/Comp/myscript.lua all the time.

Resolve 15 Beta 3 Doesn't Bundle a bmd.scriptlib

As a word of warning, if you want to have Fusion Standalone and Resolve compatibility for your UI Manager GUIs you need to double check if you use any of the classic bmd.scriptlib based functions in your Lua scripts. Resolve 15 Beta 3 does not ship with bmd.scriptlib by default.

If you do use a function like bmd. parseFilename() or eyeon.parseFilename() then you will need to extract those bmd.scriptlib functions and place a renamed version of them in your own scriptlib file or add the renamed functions inline into your Lua script.

AskUser Dialogs

At this time AskUser dialogs are particularly crashy in Resolve 15 Beta 3 release so a pure UI Manager GUI works better if you want your code to run in both Fusion Standalone and Resolve. I have had a lazy habit of using AskUser dialogs in the past for a quick OK confirmation dialog in a larger UI Manager GUI but that's not wise thing to do anymore if you want Resolve users to succeed in running your scripted tools with the current crop of Resolve 15 Beta releases.

I expect the AskUser dialog issues will be fixed in Resolve eventually but have no idea of the timescale.

Using Fake PathMap like shortcodes for relative like image paths

In Atomizer for Reactor v2.0 I used a pre-processor function on the description text to allow emoticon images to be written into the text using a Pathmap like shortcode like <img src="Emoticons:/wink.png"> in the atom description field. Then the following snippets of code that were extracted from Atomizer turns that PathMap like relative image loading URL into an absolute filepath to the image resource that makes the ui:TextEdit happy:
Code: [Select all] [Expand/Collapse] [Download] (Loose Code Snippets.lua)
  1. ------------------------------------------------------------------------
  2. -- Return a string with the directory path where the Lua script was run from
  3. -- If the script is run by pasting it directly into the Fusion Console define a fallback path
  4. -- fileTable = GetScriptDir('Reactor:/System/UI/Atomizer.lua')
  5. function GetScriptDir(fallback)
  6.     if debug.getinfo(1).source == '???' then
  7.         -- Fallback absolute filepath
  8.         return parseFilename(app:MapPath(fallback))
  9.     else
  10.         -- Filepath coming from the Lua script's location on disk
  11.         return parseFilename(app:MapPath(string.sub(debug.getinfo(1).source, 2)))
  12.     end
  13. end
  14.  
  15. -- ... snip ...
  16.  
  17. -- Add emoticon support for local images like <img src="Emoticons:/wink.png">
  18. -- Example: dump(EmoticonParse([[<img src="Emoticons:/wink.png">]]))
  19. function EmoticonParse(str)
  20.     return string.gsub(str, '[Ee]moticons:/', emoticonsDir)
  21. end
  22.  
  23. -- ... snip ...
  24.  
  25. -- Find the Icons folder
  26. -- If the script is run by pasting it directly into the Fusion Console define a fallback path
  27. fileTable = GetScriptDir('Reactor:/System/UI/Atomizer.lua')
  28.  
  29. -- Load the emoticons as standalone PNG image resources
  30. emoticonsDir = fileTable.Path .. 'Emoticons' .. osSeparator
  31.  
  32. -- ... snip - UI Manager code with the text updating function ...
  33.  
  34. function win.On.DescriptionText.TextChanged(ev)
  35. -- print('[Description Preview] Updating the HTML preview')
  36.  
  37. -- Force the HTML code into the rendering engine
  38. -- Add HTML entity encoding and emoticon support for local images like <img src="Emoticons:/wink.png">
  39. itm.HTMLPreview.HTML = EmoticonParse(itm.DescriptionText.PlainText)
  40. end

Convert Unicode characters into HTML entities

Also if you are placing user entered text/html text entry code into a ui:TextEdit field for rich text rendered output you might enjoy this function I put together in Atomizer that deals with the encoding of common Unicode characters into HTML named entities. There might be a shorter more compact way to code this feature but this met my needs and was reliable.

You can run the Lua function like this: EncodeHTML('¿')
Code: [Select all] [Expand/Collapse] [Download] (Unicode Encode To HTML Entities.lua)
  1. ------------------------------------------------------------------------
  2. -- Convert Unicode characters into HTML entities
  3. -- Example: EncodeHTML('¿')
  4. function EncodeHTML(txt)
  5.     if txt ~= nil then
  6.         htmlCharacters = {
  7.             {pattern = '¡', replace = '&iexcl;'},
  8.             {pattern = '¿', replace = '&iquest;'},
  9.             {pattern = '·', replace = '&middot;'},
  10.             {pattern = '«', replace = '&laquo;'},
  11.             {pattern = '»', replace = '&raquo;'},
  12.             {pattern = '〈', replace = '&#x3008;'},
  13.             {pattern = '〉', replace = '&#x3009;'},
  14.             {pattern = '§', replace = '&sect;'},
  15.             {pattern = '¶', replace = '&para;'},
  16.             {pattern = '%[', replace = '&#91;'},
  17.             {pattern = '%]', replace = '&#93;'},
  18.             {pattern = '‰', replace = '&permil;'},
  19.             {pattern = '†', replace = '&dagger;'},
  20.             {pattern = '‡', replace = '&Dagger;'},
  21.             {pattern = '¨', replace = '&uml;'},
  22.             {pattern = '°', replace = '&deg;'},
  23.             {pattern = '©', replace = '&copy;'},
  24.             {pattern = '®', replace = '&reg;'},
  25.             {pattern = '∇', replace = '&nabla;'},
  26.             {pattern = '∈', replace = '&isin;'},
  27.             {pattern = '∉', replace = '&notin;'},
  28.             {pattern = '∋', replace = '&ni;'},
  29.             {pattern = '±', replace = '&plusmn;'},
  30.             {pattern = '÷', replace = '&divide;'},
  31.             {pattern = '×', replace = '&times;'},
  32.             {pattern = '≠', replace = '&ne;'},
  33.             {pattern = '¬', replace = '&not;'},
  34.             {pattern = '√', replace = '&radic;'},
  35.             {pattern = '∞', replace = '&infin;'},
  36.             {pattern = '∠', replace = '&ang;'},
  37.             {pattern = '∧', replace = '&and;'},
  38.             {pattern = '∨', replace = '&or;'},
  39.             {pattern = '∩', replace = '&cap;'},
  40.             {pattern = '∪', replace = '&cup;'},
  41.             {pattern = '∫', replace = '&int;'},
  42.             {pattern = '∴', replace = '&there4;'},
  43.             {pattern = '≅', replace = '&cong;'},
  44.             {pattern = '≈', replace = '&asymp;'},
  45.             {pattern = '≡', replace = '&equiv;'},
  46.             {pattern = '≤', replace = '&le;'},
  47.             {pattern = '≥', replace = '&ge;'},
  48.             {pattern = '⊂', replace = '&sub;'},
  49.             {pattern = '⊄', replace = '&nsub;'},
  50.             {pattern = '⊃', replace = '&sup;'},
  51.             {pattern = '⊆', replace = '&sube;'},
  52.             {pattern = '⊇', replace = '&supe;'},
  53.             {pattern = '⊕', replace = '&oplus;'},
  54.             {pattern = '⊗', replace = '&otimes;'},
  55.             {pattern = '⊥', replace = '&perp;'},
  56.             {pattern = '◊', replace = '&loz; '},
  57.             {pattern = '♠', replace = '&spades;'},
  58.             {pattern = '♣', replace = '&clubs;'},
  59.             {pattern = '♥', replace = '&hearts;'},
  60.             {pattern = '♦', replace = '&diams;'},
  61.             {pattern = '¤', replace = '&curren;'},
  62.             {pattern = '¢', replace = '&cent;'},
  63.             {pattern = '£', replace = '&pound;'},
  64.             {pattern = '¥', replace = '&yen;'},
  65.             {pattern = '€', replace = '&euro;'},
  66.             {pattern = '¹', replace = '&sup1;'},
  67.             {pattern = '½', replace = '&frac12;'},
  68.             {pattern = '¼', replace = '&frac14;'},
  69.             {pattern = '²', replace = '&sup2;'},
  70.             {pattern = '³', replace = '&sup3;'},
  71.             {pattern = '¾', replace = '&frac34;'},
  72.             {pattern = 'ª', replace = '&ordf;'},
  73.             {pattern = 'ƒ', replace = '&fnof;'},
  74.             {pattern = '™', replace = '&trade;'},
  75.             {pattern = 'β', replace = '&beta;'},
  76.             {pattern = 'Δ', replace = '&Delta;'},
  77.             {pattern = 'ϑ', replace = '&thetasym;'},
  78.             {pattern = 'Θ', replace = '&Theta;'},
  79.             {pattern = 'ι', replace = '&iota;'},
  80.             {pattern = 'λ', replace = '&lambda;'},
  81.             {pattern = 'Λ', replace = '&Lambda;'},
  82.             {pattern = 'μ', replace = '&mu;'},
  83.             {pattern = 'µ', replace = '&micro;'},
  84.             {pattern = 'ξ', replace = '&xi;'},
  85.             {pattern = 'Ξ', replace = '&Xi;'},
  86.             {pattern = 'π', replace = '&pi;'},
  87.             {pattern = 'ϖ', replace = '&piv;'},
  88.             {pattern = 'Π', replace = '&Pi;'},
  89.             {pattern = 'ρ', replace = '&rho;'},
  90.             {pattern = 'σ', replace = '&sigma;'},
  91.             {pattern = 'ς', replace = '&sigmaf;'},
  92.             {pattern = 'Σ', replace = '&Sigma;'},
  93.             {pattern = 'τ', replace = '&tau;'},
  94.             {pattern = 'υ', replace = '&upsilon;'},
  95.             {pattern = 'ϒ', replace = '&upsih;'},
  96.             {pattern = 'φ', replace = '&phi;'},
  97.             {pattern = 'Φ', replace = '&Phi;'},
  98.             {pattern = 'χ', replace = '&chi;'},
  99.             {pattern = 'ψ', replace = '&psi;'},
  100.             {pattern = 'Ψ', replace = '&Psi;'},
  101.             {pattern = 'ω', replace = '&omega;'},
  102.             {pattern = 'Ω', replace = '&Omega;'},
  103.         }
  104.  
  105.         for i,val in ipairs(htmlCharacters) do
  106.             txt = string.gsub(txt, htmlCharacters[i].pattern, htmlCharacters[i].replace)
  107.         end
  108.     end
  109.  
  110.     return txt
  111. end
You do not have the required permissions to view the files attached to this post.
Last edited by AndrewHazelden on Fri May 25, 2018 8:33 am, edited 1 time in total.

User avatar
Midgardsormr
Fusionista
Posts: 936
Joined: Wed Nov 26, 2014 8:04 pm
Location: Los Angeles, CA, USA
Been thanked: 26 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#139

Post by Midgardsormr » Tue May 22, 2018 5:32 pm

AndrewHazelden wrote:
Tue May 22, 2018 5:06 pm
. Is it mostly translating IUP based Lua scripts, or new development work?

It's all new stuff at the moment. Springboarding from VersionControl, I've been working on a script to fetch renders from disk, make Loaders, and then wire together a starting back-to-beauty assembly from the buffers. I've really expanded my skills with these two projects!

User avatar
AndrewHazelden
Fusionator
Posts: 1219
Joined: Fri Apr 03, 2015 3:20 pm
Location: West Dover, Nova Scotia, Canada
Been thanked: 11 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#140

Post by AndrewHazelden » Tue May 22, 2018 5:42 pm

Midgardsormr wrote:
Tue May 22, 2018 5:32 pm
I've really expanded my skills with these two projects!
Awesome! :)

User avatar
Miltos
Fusionista
Posts: 433
Joined: Wed Aug 06, 2014 2:18 am
Contact:

Re: Building GUIs With Fusion's UI Manager

#141

Post by Miltos » Fri May 25, 2018 7:19 am

The work you guys do here is mind-blowing.

User avatar
AndrewHazelden
Fusionator
Posts: 1219
Joined: Fri Apr 03, 2015 3:20 pm
Location: West Dover, Nova Scotia, Canada
Been thanked: 11 times
Contact:

Automatically Display the Selected Node in the Viewer Window

#142

Post by AndrewHazelden » Fri Jun 08, 2018 7:59 pm

The ViewSelectedNode.fu config file will automatically display the currently selected node's output in the Fusion viewer window. This is done with a .fu file based Event{} entry that intercepts the native Comp_Activate_Tool action by appending our own custom Lua code.

This example works with Fusion 9.0.2 and Resolve 15 Beta 4.

Installing the ViewSelectedNode.fu File

Step 1. Download the ViewSelectedNode.fu file below:
Code: [Select all] [Expand/Collapse] [Download] (ViewSelectedNode.fu)
  1. --[[--
  2. ==============================================================================
  3. ViewSelectedNode.fu - v1.1 2018-06-08
  4. ==============================================================================
  5. Created by : Andrew Hazelden [andrew@andrewhazelden.com]
  6.  
  7. ==============================================================================
  8. Overview
  9. ==============================================================================
  10. The "ViewSelectedNode.fu" config file displays the currently selected node in the Fusion viewer window. This is done with a .fu file based Event{} entry that intercepts the native "Comp_Activate_Tool" action by appending our own custom Lua code.
  11.  
  12. You can adjust the code in this .fu file to change it so you can automatically target the left or right viewer context by swapping the double dash -- comments on the lines:
  13.  
  14. -- Resolve 15 Viewer Windows
  15. viewer = cmp:GetPreviewList().LeftView
  16. -- viewer = cmp:GetPreviewList().RightView
  17.  
  18. and
  19.  
  20. -- Fusion 9 Viewer Windows
  21. viewer = cmp:GetPreviewList().Left
  22. -- viewer = cmp:GetPreviewList().Right
  23.  
  24.  
  25. The key part of this event example is the line:
  26. rets = self:Default(ctx, args)
  27.  
  28. If you place your own custom code above that line in the Event{} block, Fusion will run your Lua command just before it carries out the action. If you place your own custom code after the that line in the Event{} block, Fusion will run your Lua commands just after the action occurs.
  29.  
  30. A .fu file based Event{} entry is the new Fusion 9 centric replacement for the previous Fusion 7.x era "Events and Callbacks" technique. The older event system was described in the "Fusion 8 Scripting Guide.pdf" file on page 25.
  31.  
  32. ==============================================================================
  33. Installation
  34. ==============================================================================
  35. Copy the ViewSelectedNode.fu file to the Fusion user prefs "Config:/" PathMap folder.
  36.  
  37. Restart Fusion for the example to be activated. When you add new nodes, or select a node in your Fusion comp the "Comp_Activate_Tool" actions that happen will cause the active node's output into your Fusion viewer window automatically.
  38.  
  39. ==============================================================================
  40. Listing all of the Actions
  41. ==============================================================================
  42. Here is a short code chunk you can use to print out a list of all the actions that exist in Fusion. This is handy information to know if you want to try adding a new event that is used to override the normal operaton of a action:
  43.  
  44. -- Track the actions that are available in Fusion
  45. local actionList = fu.ActionManager:GetActions()
  46.  
  47. -- List each action sequentially
  48. actionCount = 0
  49. for i, act in ipairs(actionList) do
  50.     if not act:Get('Parent') then
  51.         print(act.ID)
  52.         actionCount = actionCount + 1
  53.     end
  54. end
  55.  
  56. -- Count the total number of actions
  57. print('[' .. actionCount .. ' Actions Found]')
  58.  
  59. ==============================================================================
  60. Further Action Reference Material
  61. ==============================================================================
  62. You can take the Event {} action intercepting concept that is demonstrated in this example file further by applying it to any other action that exists in Fusion.
  63.  
  64. The We Suck Less Forum based UI Manager Thread has a script called Action Listener that lets you inspect actions as they happen in your composite:
  65. https://www.steakunderwater.com/wesuckless/viewtopic.php?f=6&t=1411&p=11465#p11465
  66.  
  67. ==============================================================================
  68. --]]--
  69.  
  70. {
  71.     Event {
  72.         -- Add a new event that intercepts the Action
  73.         Action = "Comp_Activate_Tool",
  74.         Targets = {
  75.             Composition = {
  76.                 Execute = [[
  77. -- Run the Action as the first step
  78. rets = self:Default(ctx, args)
  79.  
  80. -- Get the pointer for the current foreground comp
  81. cmp = obj:Comp()
  82.    
  83. -- Read the active node selection in the Flow view
  84. selectedNode = cmp.ActiveTool
  85. if selectedNode then
  86.   -- Viewer window context
  87.   local viewer = nil
  88.  
  89.   -- Check if Resolve or Fusion Standalone is active and get the left or right viewer
  90.   host = fusion:MapPath('Fusion:/')
  91.   if string.lower(host):match('resolve') then
  92.     -- Resolve 15 Viewer Windows
  93.     viewer = cmp:GetPreviewList().LeftView
  94.     -- viewer = cmp:GetPreviewList().RightView
  95.   else
  96.     -- Fusion 9 Viewer Windows
  97.     viewer = cmp:GetPreviewList().Left
  98.     -- viewer = cmp:GetPreviewList().Right
  99.   end
  100.  
  101.     -- Show the selected node in the viewer window
  102.     if viewer then
  103.       viewer:ViewOn(selectedNode)
  104.     end
  105. end
  106. ]]
  107.             },
  108.         },
  109.     },
  110.  
  111. }

Step 2. Copy the downloaded ViewSelectedNode.fu file into the Fusion user prefs Config:/ PathMap folder.

Step 3. Restart Fusion for the new .fu file to be activated. When you add new nodes, or select a node in your Fusion comp the "Comp_Activate_Tool" actions that happen will cause the active node's output into your Fusion viewer window automatically.

Targeting the Left or Right Viewer Window

If you want to, you can adjust the code in the .fu file to change it so you are automatically targeting the left or right viewer context by swapping the placement of the double dash -- comment entries on the following lines of code:

Code: Select all

-- Resolve 15 Viewer Windows
viewer = cmp:GetPreviewList().LeftView
-- viewer = cmp:GetPreviewList().RightView

and

Code: Select all

-- Fusion 9 Viewer Windows
viewer = cmp:GetPreviewList().Left
-- viewer = cmp:GetPreviewList().Right

Changing the Event Trigger

If you don't like the effect of the active node selection driving the active content in the viewer window, you could change the code so the AddTool event is used instead. This way the viewer will changes its active node focus when a new node is added to the comp.

To make this edit change the following line of .fu code:

Code: Select all

-- Add a new event that intercepts the Action
Action = "Comp_Activate_Tool",

Over to the AddTool Action:

Code: Select all

-- Add a new event that intercepts the Action
Action = "AddTool",

User avatar
AndrewHazelden
Fusionator
Posts: 1219
Joined: Fri Apr 03, 2015 3:20 pm
Location: West Dover, Nova Scotia, Canada
Been thanked: 11 times
Contact:

Fusion Registry Scanner Script

#143

Post by AndrewHazelden » Sat Jun 09, 2018 5:46 pm

The Fusion Registry Scanner comp script generates a super detailed report of Fusion's active libraries/plugins/nodes/fuses by probing Fusion's core registry. The resulting UserData:/Registry.log text file that is saved is automatically opened up in the programmer's text editor you have defined in your Fusion preference's "Script Editor" setting.

This script is a great research tool that will enable you to dig deeper into Fusion and find out more about the internals of the compositing package. You can really take your Fusion pipeline tool development efforts to the next level if you are armed with a Fusion registry report, and the Fusion Script Help Browser. These tools allow you to bypass the boundaries of Fusion's own documentation and venture into using undocumented features for power user level access to exotic Fusion features you would never know about otherwise. ;)

Download the Lua Script

This script works with Fusion 9.0.2 and Resolve 15 Beta 4.

Code: [Select all] [Expand/Collapse] [Download] (Fusion Registry Scanner.lua)
  1. VERSION = '1.0 2018-06-09'
  2. --[[--
  3. Fusion Registry Scanner.lua
  4. By Andrew Hazelden <andrew@andrewhazelden.com>
  5.  
  6. # Overview #
  7.  
  8. The "Fusion Registry Scanner" comp script generates a super detailed report of Fusion's active libraries/plugins/nodes/fuses by probing Fusion's core registry. The resulting "UserData:/Registry.log" text file that is saved is automatically opened up in the programmer's text editor you have defined in your Fusion preference's "Script Editor" setting.
  9.  
  10. This script is a great research tool that will enable you to dig deeper into Fusion and find out more about the internals of the compositing package. You can really take your Fusion pipeline tool development efforts to the next level if you are armed with a Fusion registry report, and the Fusion Script Help Browser (https://www.steakunderwater.com/wesuckless/viewtopic.php?p=11343#p11343). These tools allow you to bypass the boundaries of Fusion's own documentation and venture into using undocumented features for power user level access to exotic Fusion features you would never know about otherwise.  ;)
  11.  
  12. This script works with Fusion 9.0.2 and Resolve 15 Beta 4.
  13.  
  14. # For More Info on the Registry #
  15.  
  16. If you want to read the official documentation from BMD on the Fusion Registry, you can open the Fusion 8 Script Manual.pdf file and flip to page 110 where the fusion:GetRegList() function is covered.
  17.  
  18.  
  19. # Fusion Registry Types #
  20.  
  21. This is a short list from the Fusion 8 Scripting Guide of the types of core registry objects in Fusion:
  22.  
  23.     CT_Tool - All tools
  24.     CT_Mask - Mask tools only
  25.     CT_SourceTool - Creator tools (images/3D/particles) all
  26.     of which don’t require an input image CT_ParticleTool Particle tools
  27.     CT_Modifier - Modifiers
  28.     CT_ImageFormat - The available image and movie formats
  29.     CT_View - The different sections of the interface
  30.     CT_GLViewer - All kinds of viewers
  31.     CT_PreviewControl - PreviewControls in the viewer
  32.     CT_InputControl - The Input controls
  33.     CT_BinItem - Fusion Standalone Bin items
  34.  
  35. # Example Registry Scanner Output #
  36.  
  37. This is an partial snippet of the output from the script:
  38.  
  39. Registry Scanner - 1.0 2018-06-09
  40. By Andrew Hazelden <andrew@andrewhazelden.com
  41.  
  42. [Total Registry Entries Found] 993
  43.  
  44. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  45.  
  46. [Registry ID List]
  47.     [558] OpenEXRFormat
  48.  
  49. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  50.  
  51. [Registry Entries List]
  52.  
  53. [558] OpenEXRFormat
  54.         REGB_MediaFormat_CanSaveCompressed = false
  55.         REGB_MediaFormat_OneShotSave = false
  56.         REGB_Hide = false
  57.         REGB_ImageFormat_CanLoadFields = false
  58.         REGB_ImageFormat_CanScale = false
  59.         REGB_ImageFormat_CanSave24bit = false
  60.         REGB_MediaFormat_ClipSpecificInputValues = true
  61.         REGST_MediaFormat_Extension =
  62.     table: .exr
  63.         2 = .sxr
  64.  
  65.         REGI_Version = 0
  66.         REGB_SupportsDoD = false
  67.         REGB_MediaFormat_LoadLinearOnly = false
  68.         REGB_MediaFormat_CanLoad = true
  69.         REGS_Name = OpenEXRFormat
  70.         REGS_FileName = /Applications/Blackmagic Fusion 9/Fusion.app/Contents/MacOS/Plugins/openexr.plugin
  71.         REGB_MediaFormat_WantsIOClass = true
  72.         REGB_MediaFormat_CanSaveImages = true
  73.         REGS_VersionString = Built: Dec 20 2017
  74.         REGI_DataType =
  75.         REGB_MediaFormat_LoadSupportsDoD = true
  76.         REGB_MediaFormat_CanSaveAudio = false
  77.         REGI_HelpID = 0
  78.         REGI_HelpTopicID = 0
  79.         REGB_ImageFormat_CanSave32bit = false
  80.         REGB_MediaFormat_CanLoadText = false
  81.         REGB_MediaFormat_CanLoadMulti = false
  82.         REGB_ImageFormat_CanSave8bit = false
  83.         REGB_ImageFormat_CanSaveFields = false
  84.         REGB_MediaFormat_SaveSupportsDoD = true
  85.         REGI_ClassType = 1572864
  86.         REGB_Unpredictable = false
  87.         REGB_MediaFormat_OneShotLoad = false
  88.         REGB_MediaFormat_CanSaveText = false
  89.         REGB_MediaFormat_CanSaveMIDI = false
  90.         REGI_MediaFormat_Priority = 0
  91.         REGB_MediaFormat_WantsUnbufferedIOClass = false
  92.         REGI_InputDataType =
  93.         REGB_MediaFormat_CanSave = true
  94.         REGB_ControlView = false
  95.         REGI_Priority = 0
  96.         REGB_MediaFormat_CanLoadAudio = false
  97.         REGB_MediaFormat_CanSaveMulti = false
  98.         REGB_MediaFormat_SaveLinearOnly = false
  99.         REGS_ID = OpenEXRFormat
  100.         REGS_MediaFormat_FormatName = OpenEXR Files
  101.         REGB_MediaFormat_CanLoadMIDI = false
  102.         REGB_MediaFormat_CanLoadImages = true
  103.  
  104. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  105.  
  106. # Interesting Registry Entries #
  107.  
  108. If you are a pipeline programmer who wants to check what media formats are supported in Fusion 9/Resolve 15 you might find a few of the more interesting registry entry records here:
  109.  
  110.     FFMPEGFileFormats
  111.     QuickTimeAudio
  112.     QuickTimeMovies
  113.     JpegFormat
  114.     OpenEXRFormat
  115.     PNGFormat
  116.     TargaFormat
  117.     TiffFormat
  118.  
  119. --]]--
  120.  
  121. -- Check which OS the script is running on
  122. platform = (FuPLATFORM_WINDOWS and 'Windows') or (FuPLATFORM_MAC and 'Mac') or (FuPLATFORM_LINUX and 'Linux')
  123.  
  124.  
  125. -- Open a textfile for editing
  126. -- Example: OpenDocument('Open Registry.log in Script Editor', '/Applications/BBEdit.app', 'UserData:/Registry.log')
  127. function OpenDocument(title, appPath, docPath)
  128.     local command = ''
  129.  
  130.     -- Use the correct command prompt launching syntax for each OS
  131.     if platform == 'Windows' then
  132.         -- Running on Windows
  133.         command = 'start "" "' .. comp:MapPath(appPath) .. '" "' .. comp:MapPath(docPath) .. '" &'
  134.     elseif platform == 'Mac' then
  135.         -- Running on Mac
  136.         command = 'open -a "' .. comp:MapPath(appPath) .. '" "' .. comp:MapPath(docPath) .. '" &'
  137.     elseif platform == "Linux" then
  138.         -- Running on Linux
  139.         command = '"' .. comp:MapPath(appPath) .. '" "' .. comp:MapPath(docPath) .. '" &'
  140.     else
  141.         print('[Error] There is an invalid Fusion platform detected')
  142.         return
  143.     end
  144.  
  145.     -- Debug printing output:
  146.     comp:Print('[' .. title .. ']\n')
  147.     comp:Print('\t[App] "' .. appPath .. '"\n')
  148.     comp:Print('\t[Document] "' .. docPath .. '"\n')
  149.     comp:Print('\t[Launch Command] ' .. tostring(command) .. '\n\n')
  150.    
  151.     -- Run the command prompt task
  152.     os.execute(command)
  153. end
  154.  
  155.  
  156. -- Convert a Lua table to a string
  157. -- Example: TableToString({})
  158. -- https://stackoverflow.com/questions/9168058/how-to-dump-a-table-to-console
  159. function TableToString(tbl)
  160.     if type(tbl) == 'table' then
  161.         local str = '\n'
  162.        
  163.         for i,val in pairs(tbl) do
  164.             if i == 1 then
  165.                 str = str .. '\ttable: ' .. TableToString(val) .. '\n'
  166.             else
  167.                 str = str .. '\t\t' .. i .. ' = ' .. TableToString(val) .. '\n'
  168.             end
  169.         end
  170.        
  171.         return str
  172.     else
  173.         return tostring(tbl)
  174.     end
  175. end
  176.  
  177.  
  178. -- Scan the complete Fusion registry
  179. function RegScan()
  180.     local regStr = ''
  181.     local idStr = ''
  182.     i = 1
  183.     reg = fusion:GetRegList()
  184.     for k,v in ipairs(reg) do
  185.         if v ~= nil then
  186.             attr = v:GetAttrs()
  187.             -- dump(attr)
  188.            
  189.             -- Append another registry entry as a text string
  190.             regStr = regStr .. '\n'
  191.             regStr = regStr .. '[' .. i .. '] ' .. tostring(attr.REGS_ID)
  192.             regStr = regStr .. TableToString(attr)
  193.             regStr = regStr .. '\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n'
  194.            
  195.             -- Append another registry ID entry as a text string
  196.             idStr = idStr .. '\t[' .. i .. '] ' .. tostring(attr.REGS_ID) .. '\n'
  197.            
  198.             -- Debug print the registry ID
  199.             -- print('[' .. i .. '] ' .. tostring(attr.REGS_ID))
  200.             i = i + 1
  201.         end
  202.     end
  203.    
  204.     -- Build the final registry objects list as a text string
  205.     local outputStr = ''
  206.     local topHeader = '\n[Total Registry Entries Found] ' .. i .. '\n'
  207.     local idHeader = '\n[Registry ID List]\n'
  208.     local regHeader = '\n[Registry Entries List]\n'
  209.     local dividerStr = '\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n'
  210.    
  211.     outputStr = outputStr ..'Fusion Registry Scanner - ' .. tostring(VERSION) .. '\n'
  212.     outputStr = outputStr ..'By Andrew Hazelden <andrew@andrewhazelden.com\n'
  213.     outputStr = outputStr .. topHeader .. dividerStr
  214.     outputStr = outputStr .. idHeader .. idStr .. dividerStr
  215.     outputStr = outputStr .. regHeader .. regStr .. '[Done]' .. dividerStr
  216.    
  217.     -- Debug print the finished string
  218.     -- dump(outputStr)
  219.     return outputStr
  220. end
  221.  
  222.  
  223. -- Main is where the magic happens
  224. function Main()
  225.     -- Write a startup message to the active comp's Console view
  226.     comp:Print('\n')
  227.     comp:Print('---------------------------------------------\n')
  228.     comp:Print('Fusion Registry Scanner - ' .. tostring(VERSION) .. '\n')
  229.     comp:Print('By Andrew Hazelden <andrew@andrewhazelden.com\n')
  230.     comp:Print('---------------------------------------------\n')
  231.     comp:Print('\n')
  232.  
  233.     -- Check if Fusion has a defined "Script Editor" tool
  234.     local editorPath = fu:GetPrefs('Global.Script.EditorPath')
  235.     if editorPath == nil or editorPath == '' then
  236.         -- Error: There was no script editor specified in the Fusion prefs
  237.        
  238.         -- Fallback message:
  239.         comp:Print('[Fusion Registry Scanner] The "Editor Path" is empty in Fusion. Please choose a text editor in the Fusion Preferences "Global and Default Settings > Script > Editor Path" section.\n')
  240.        
  241.         -- Display the fusion preferences window and switch to the "Script" section
  242.         app:ShowPrefs('PrefsScript')
  243.     else
  244.         -- A script editor was specified in the Fusion prefs
  245.        
  246.         -- Generate the Registry.log absolute filepath so it is saved to the base of the Fusion user preferences folder
  247.         local regFilepath = comp:MapPath('UserData:/Registry.log')
  248.        
  249.         -- Write out the log file
  250.         regFP, err = io.open(regFilepath,'w')
  251.         if err then
  252.             -- There was an error with a nil file pointer
  253.             comp:Print('[Error Opening File for Writing] ' .. tostring(regFilepath) .. '\n')
  254.             return
  255.         else
  256.             comp:Print('[Writing Registry] ' .. tostring(regFilepath) .. '\n\n')
  257.            
  258.             -- Scan the complete Fusion registry and then write it to disk
  259.             regFP:write(RegScan())
  260.             --regFP:write('\n')
  261.            
  262.             -- Close the file pointer on the output textfile
  263.             regFP:close()
  264.            
  265.             -- Open the file in the default script editor
  266.             OpenDocument('Open Registry.log in Script Editor', editorPath, regFilepath)
  267.         end
  268.     end
  269. end
  270.  
  271. -- Run the main function
  272. Main()
  273. print('[Done]')

Script Installation Instructions

Step 1. After you download this lua script copy it to the Fusion user preferences Scripts:/Comp/Andrew Hazelden/ PathMap folder.

Install the Lua Script.png

Step 2. Run the script from the Fusion Script > Fusion Registry Scanner Menu.

Run the Script in Fusion.png

Step 3. If you don't have a Script Editor tool defined in Fusion's Preferences then the message Please choose a text editor in the Fusion Preferences "Global and Default Settings > Script > Editor Path" section. will be printed in the Console view.

Fusion Script Preferences.png

After you set this preference you will need to re-run this script.

Step 4. A generated Fusion Registry output will be saved as a text file to the UserData:/Registry.log PathMap location which is the base of the Fusion user preferences folder for the current user account.

Registry.log Filepath on Disk.png

Example Fusion Registry Scanner Output

Console View

After you run the script the Fusion Console window will show a short info message about the file that was saved and what program was run to load the log file.

Console Output.png

Viewing the Registry.log File


This is what you will see when the new registry log file is opened up in your text editor.

Registry.log Output in BBEdit 1.png
Registry.log Output in BBEdit 2.png

Registry.log Contents

This is an partial snippet of the output from the script:

Code: Select all

Fusion Registry Scanner - 1.0 2018-06-09
By Andrew Hazelden <andrew@andrewhazelden.com

[Total Registry Entries Found] 993

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

[Registry ID List]
	[558] OpenEXRFormat

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

[Registry Entries List]

[558] OpenEXRFormat
		REGB_MediaFormat_CanSaveCompressed = false
		REGB_MediaFormat_OneShotSave = false
		REGB_Hide = false
		REGB_ImageFormat_CanLoadFields = false
		REGB_ImageFormat_CanScale = false
		REGB_ImageFormat_CanSave24bit = false
		REGB_MediaFormat_ClipSpecificInputValues = true
		REGST_MediaFormat_Extension = 
	table: .exr
		2 = .sxr

		REGI_Version = 0
		REGB_SupportsDoD = false
		REGB_MediaFormat_LoadLinearOnly = false
		REGB_MediaFormat_CanLoad = true
		REGS_Name = OpenEXRFormat
		REGS_FileName = /Applications/Blackmagic Fusion 9/Fusion.app/Contents/MacOS/Plugins/openexr.plugin
		REGB_MediaFormat_WantsIOClass = true
		REGB_MediaFormat_CanSaveImages = true
		REGS_VersionString = Built: Dec 20 2017
		REGI_DataType = 
		REGB_MediaFormat_LoadSupportsDoD = true
		REGB_MediaFormat_CanSaveAudio = false
		REGI_HelpID = 0
		REGI_HelpTopicID = 0
		REGB_ImageFormat_CanSave32bit = false
		REGB_MediaFormat_CanLoadText = false
		REGB_MediaFormat_CanLoadMulti = false
		REGB_ImageFormat_CanSave8bit = false
		REGB_ImageFormat_CanSaveFields = false
		REGB_MediaFormat_SaveSupportsDoD = true
		REGI_ClassType = 1572864
		REGB_Unpredictable = false
		REGB_MediaFormat_OneShotLoad = false
		REGB_MediaFormat_CanSaveText = false
		REGB_MediaFormat_CanSaveMIDI = false
		REGI_MediaFormat_Priority = 0
		REGB_MediaFormat_WantsUnbufferedIOClass = false
		REGI_InputDataType = 
		REGB_MediaFormat_CanSave = true
		REGB_ControlView = false
		REGI_Priority = 0
		REGB_MediaFormat_CanLoadAudio = false
		REGB_MediaFormat_CanSaveMulti = false
		REGB_MediaFormat_SaveLinearOnly = false
		REGS_ID = OpenEXRFormat
		REGS_MediaFormat_FormatName = OpenEXR Files
		REGB_MediaFormat_CanLoadMIDI = false
		REGB_MediaFormat_CanLoadImages = true

Interesting Fusion Registry Entries

If you are a pipeline programmer who wants to check what media formats are supported in Fusion 9/Resolve 15 you might find a few of the more interesting registry entry records here:

  • FFMPEGFileFormats
  • QuickTimeAudio
  • QuickTimeMovies
  • JpegFormat
  • OpenEXRFormat
  • PNGFormat
  • TargaFormat
  • TiffFormat

Fusion Registry Types

This is a short list from the Fusion 8 Scripting Guide of the types of core registry objects in Fusion:

  • CT_Tool - All tools
  • CT_Mask - Mask tools only
  • CT_SourceTool - Creator tools (images/3D/particles) all
  • of which don’t require an input image CT_ParticleTool Particle tools
  • CT_Modifier - Modifiers
  • CT_ImageFormat - The available image and movie formats
  • CT_View - The different sections of the interface
  • CT_GLViewer - All kinds of viewers
  • CT_PreviewControl - PreviewControls in the viewer
  • CT_InputControl - The Input controls
  • CT_BinItem - Fusion Standalone Bin items

For More Info on the Fusion Registry

If you want to read the official documentation from BMD on the Fusion Registry, you can open up the Fusion 8 Script Manual.pdf file and flip to page 110 where the fusion:GetRegList() function is covered.
You do not have the required permissions to view the files attached to this post.

User avatar
AndrewHazelden
Fusionator
Posts: 1219
Joined: Fri Apr 03, 2015 3:20 pm
Location: West Dover, Nova Scotia, Canada
Been thanked: 11 times
Contact:

Using a Script to Add Macros to a Comp

#144

Post by AndrewHazelden » Sun Jun 17, 2018 12:56 pm

I noticed a question on the BMD Fusion forum today by Nick Verlinden that asked how to use a script to add a macro to a composite after a specific tool. Here's a look at a few of the different ways that task could be achieved.

Adding a Macro Using a .fu Hotkeys Entry

A Config:/ .fu hotkeys entry can be used to add a macro to your comp when a specific hotkey is pressed. This hotkey entry will place the newly added macro right after your currently selected node and connect them together automatically.

Code: [Select all] [Expand/Collapse] [Download] (AddSettings Hotkey.fu)
  1. {
  2.     Hotkeys
  3.     {
  4.         Target = "FlowView",
  5.        
  6.         Y = "AddSetting{filename = 'Macros:/YourMacroFile.setting'}",
  7.     },
  8. }

When you restart Fusion this new Hotkeys entry is visible in the Hotkeys Manager window's Views > Flow section:

Hotkeys Manager view.png

Adding a Macro Using comp:Paste()

A Lua scripted approach can be used to add a new macro to your composite right after a specific tool:

Code: [Select all] [Expand/Collapse] [Download] (Add Macro Using Paste.lua)
  1. -- Set Blur1 to be the actively selected tool
  2. comp:SetActiveTool(comp:FindTool("Blur1"))
  3.  
  4. -- Load the macro by reading the file off disk as a Lua table and then paste it into the comp
  5. comp:Paste(bmd.readfile(comp:MapPath("Macros:/YourMacroFile.setting")))

Finding the Node

This script snippet starts out by finding the "Blur1" node using its name in the comp. Then it translates that node name into the pointer value in memory for the node:

Code: Select all

==comp:FindTool("Blur1")
-- Blur (0x0x7f84b20c0000) [App: 'Fusion' on 127.0.0.1, UUID: b59420bf-962b-4971-be37-4cab2c24119c]

Setting the Active Tool

The comp:SetActiveTool() function then selects this node in the flow view in Fusion. This makes the Blur1 node the active tool.

Selected Blur Node.png

Translating the Macro:/ PathMap

The next line of the script snippet starts out by using comp:MapPath() to translate the relative PathMap location of Macros:/ into an absolute filepath. In my system, this command turns the relative Macros:/YourMacroFile.setting filepath into the expanded absolute filepath location of:

/Users/andrew/Library/Application Support/Blackmagic Design/Fusion/Macros/YourMacroFile.setting

PathMap Translation.png

Reading in the Macro File Contents

Then the bmd.readfile() function loads the macro's text file based .settings contents from disk into a new Lua table element. We can use the dump command which is written in short form as == to print this Lua table out in the console if we want.

bmd.readfile.png

Pasting in the Macro

Finally the comp:Paste() function pastes the Lua table element of the macro data into the comp as a new node that is visible in the flow view.

Added a new Macro.png

If you have the Reactor package manager based "UI Manager Lua & Python Examples" atom package installed there is a script called the "FusionScript Help Browser" that can give you help information about the Fusion specific commands that can be run from Lua like comp:Paste():

FusionScript Help Browser Composition Paste.png

The "Fusion 8 Script Manual.pdf" guide covers the composition.paste() command on page 82.


Locking and Unlocking a Comp

When you add a macro node to a comp using a scripted approach, you have the option of suppressing any of the file dialogs that would appear. These dialogs occur when a Loader/Saver/Alembic Mesh3D/FBX Mesh3D/FBX Exporter node is present in a Macro and those nodes have an empty Filename field.

This dialog suppression technique is done by adding a pair of matching Lock and Unlock commands at the top and end of your script. The lock command is run before you add a new node to the comp, and the unlock command is run after the node has been added.

Code: [Select all] [Expand/Collapse] [Download] (Locking a Fusion Comp.lua)
  1. -- Lock the comp flow area
  2. comp:Lock()
  3.  
  4. -- Do something in the script that would show a file dialog
  5. -- ..
  6.  
  7. -- Unlock the comp flow area
  8. comp:Unlock()

Adding a Macro Using Python

If you prefer to do Python scripting in Fusion, here is a version of the same "Add Macro Using Paste" script:
Code: [Select all] [Expand/Collapse] [Download] (Add Macro Using Paste.py)
  1. # Set Blur1 to be the actively selected tool
  2. comp.SetActiveTool(comp.FindTool("Blur1"))
  3.  
  4. # Load the macro by reading the file off disk and then paste it into the comp
  5. comp.Paste(bmd.readfile(comp.MapPath('Macros:/YourMacroFile.setting')))


Adding a Macro Using an Action

If you wanted to get really fancy with adding a macro to a composite, you could also use a Lua scripted "action" based approach to carry out the same task of adding a macro after a selected node:

Code: [Select all] [Expand/Collapse] [Download] (Add Macro Using Actions.lua)
  1. -- Set Blur1 to be the actively selected tool
  2. comp:SetActiveTool(comp:FindTool("Blur1"))
  3.  
  4. -- Use the AddSetting action to load the macro
  5. comp:DoAction("AddSetting", {filename = "Macros:/YourMacroFile.setting"})

Setting the Active Tool

This code snippet starts by useing comp:FindTool() to translate the node name to it's pointer. Then it selects the node in the comp using comp:SetActiveTool().

Selected Blur Node.png

Using Actions

Next we come to an interesting function called DoAction() which might be completely new to you.

At this point, I'd like to recommend you install the Reactor package manager based "UI Manager Lua & Python Examples" atom package. This will give you access to a script called "Action Listener.lua". This script can be used to get a live display of the actions that happen in Fusion while you are creating a comp as an end user.


This screenshot shows the Action Listener script's output that is displayed after you press the key combination required to run the Config:/ based AddSettings Hotkey.fu entry that was listed at the very top of this post.

Fusion Action Listener AddSetting.png

This Action Listener output looks quite cryptic at first. Let's break it down and explore what it is saying.

Code: Select all

[Event]
table: 0x0a9836a0
	when = 1529257074.013
	sender = Composition (0x0x7feb4db52e00) [App: 'Fusion' on 127.0.0.1, UUID: 851363ce-6d45-461f-a230-55bedabe7be4]
	Args = table: 0x0a983788
		filename = Macros:/YourMacroFile.setting
		_sxpos = 1639
		__flags = 1048832
		_wypos = 252
		_wxpos = 914
		_sypos = 1034
	what = AddSetting
	Rets = table: 0x0a9837d0
Sender Event Result

When an action is listed in Action Listener it typically has an entry like sender = Composition in the output. This means you would need to write in comp:DoAction() as the function to run it if you want to mimic the recorded action in your own script.

Otherwise, if an action runs in the Fusion wide scope (and not the comp level) then you would need to use the Fusion scope based fusion:DoAction() or app:DoAction() function to run it. This typically happens when you need to run Actions for new comp creation commands, or importing geometry.

What Event Result

The Action we want to inspect is listed in the Action Listener tool under the heading of what = AddSetting. This AddSetting command is the exact same item we had in our Config: .fu hotkeys file.

Args Event Result

The next thing to look at in the Action Listener window is the Args = table: result. In this section we can see a list of the items that are able to be specified as parameters to the DoAction function.

The Args table lists entries for filename, _sxpos, __flags, _wypos, _wxpos, _sypos. We are interested in the filename = Macros:/YourMacroFile.setting entry since this is where the name of the macro we want to use is specified.

The syntax of the DoAction() function goes something like this:

comp:DoAction("TheActionName", { argName1 = "YourArgValue1", argName2 = "YourArgValue2", argName3 = "YourArgValue3",}


The element "TheActionName" is where you write in the name of the actual action you want to run like "AddSetting".

The next item is a Lua table that is defined with curly braces {}. Inside this section you can list each of the arguments by name followed by their value and then a comma. If there are multiple args you want to add, a comma is used to separate each of the individual args entries. Numbers are written in as values directly without quotes, while strings can be written in using either single quotes ' ', double quotes " ", or double square brackets [[ ]].

So for our needs, we would run the AddSetting action using this Lua command:

comp:DoAction("AddSetting", {filename = "Macros:/YourMacroFile.setting"})

Added a new Macro.png

Listing All of the Actions


If you want to get a complete listing of all the actions that are present in your copy of Fusion 9/Resolve 15, this Lua script can be used to do a Console view based print-out from the ActionManager:

Code: [Select all] [Expand/Collapse] [Download] (Action Printout.lua)
  1. --[[--
  2. Action Printout v1.0 - 2018-06-17
  3. by Andrew Hazelden <andrew@andrewhazelden.com>
  4. www.andrewhazelden.com
  5.  
  6. Print a copy of the actions list to the Console.
  7.  
  8. --]]--
  9.  
  10. -- Track the actions that are available in Fusion
  11. local actionList = fu.ActionManager:GetActions()
  12.  
  13. -- Count the total number of actions
  14. actionCount = 0
  15. for i, act in ipairs(actionList) do
  16.     if not act:Get('Parent') then
  17.         actionCount = actionCount + 1
  18.     end
  19. end
  20. print('[' .. actionCount .. ' Actions Found]')
  21.  
  22. -- List each action sequentially
  23. for i, act in ipairs(actionList) do
  24.     if not act:Get('Parent') then
  25.         print(act.ID)
  26.     end
  27. end
  28.  

After you run this script, will see a Console result similar to this output that displays both the Fusion wide, and comp specific actions.

Console Actions Printout.png

Like many things in Fusion 9 and Resolve 15, actions have very little documentation at the moment besides what you can find by searching the scripting discussion threads on the WSL forum, or from code examples that can be discovered in Reactor atom packages.

As far as the process of learning how to script things in Fusion goes, the FusionScript Help Browser tool is a pretty good research tool for listing the existence of under-documented features you can access.

If we open up the FusionScript Help Browser tool and look at the ActionManager class we will see the DoAction member is listed.

FusionScript Help Browser Do Action.png

Scanning a Comp for Existing Macros

The following Lua code snippet scans the current Fusion comp to look for all of the GroupOperator and MacroOperator node RegIDs. Then it looks up their node names:
Code: [Select all] [Expand/Collapse] [Download] (Scan Comp for Macro Nodes.lua)
  1. --[[--
  2. Scan Comp for Macro Nodes - 1.0 2018-06-18
  3. By Andrew Hazelden <andrew@andrewhazelden.com>
  4. --]]--
  5.  
  6. -- Should only the currently selected nodes be displayed
  7. local showSelected = false
  8.  
  9. print('[Listing Macros]')
  10.  
  11. -- List the macros that are stored as groups
  12. print('\n[GroupOperator Based Macros]')
  13. local toollist1 = comp:GetToolList(showSelected, 'GroupOperator')
  14. for i, tool in ipairs(toollist1) do
  15.     nodeID = tool:GetAttrs().TOOLS_RegID
  16.     nodeName = tool:GetAttrs().TOOLS_Name
  17.     print('\t[' .. nodeName .. ' Macro] ' ..  nodeID)
  18. end
  19.  
  20. -- List the macros that have their controls exposed but the group expandable option disabled
  21. print('\n[MacroOperator Based Macros]')
  22. local toollist2 = comp:GetToolList(showSelected, 'MacroOperator')
  23. for i, tool in ipairs(toollist2) do
  24.     nodeID = tool:GetAttrs().TOOLS_RegID
  25.     nodeName = tool:GetAttrs().TOOLS_Name
  26.     print('\t[' .. nodeName .. ' Macro] ' ..  nodeID)
  27. end
  28.  

This gives an output in the Console that looks like this:

Code: Select all

[Listing Macros]

[GroupOperator Based Macros]
	[Z360Extract Macro] GroupOperator
	[Angular2Equirectangular Macro] GroupOperator
	[MayaBackgroundGradientEquirectangular Macro] GroupOperator
	[Group1 Macro] GroupOperator

[MacroOperator Based Macros]
	[Z360Render_1 Macro] MacroOperator
You do not have the required permissions to view the files attached to this post.

Nick Verlinden
Posts: 8
Joined: Thu Apr 12, 2018 5:29 am

Displaying a Window in the center of Resolve/Fusion

#145

Post by Nick Verlinden » Thu Jun 21, 2018 9:16 am

Hi,

I like my windows perfectly centered over the Resolve window :-)
Because I could not find a sample to display a Window from a script that is centered over the Resolve Window, I post my one below.
This is a function that you can call to show a quick message.
Line 48 is responsible for setting the Window's size, and line 49 makes sure the control layout is updated according to the newly set window size.


The only thing I haven't been able to figure out yet is how to make the window size fixed, so that the user can't resize it. Anybody know how to do that? UPDATE: found out how, check line 17 (Only tested on Windows, and the flag does seem to be MS specific), sample is updated :-)

Code: [Select all] [Expand/Collapse] [Download] (ShowMessage.lua)
  1. ----------------------------------------------------------------------------------------------------
  2. --
  3. -- ShowMessage
  4. --
  5. -- Display window with a custom error text.
  6. --
  7. ----------------------------------------------------------------------------------------------------
  8. function ShowMessage(title, msg)
  9.     -- Create window instance
  10.     win = disp:AddWindow({
  11.         ID = "WinMsg",
  12.         WindowTitle = title,
  13.         Spacing = 10,
  14.         --Geometry = {left, top, 400, 150},
  15.         WindowFlags = {
  16.             Dialog = true,
  17.             MSWindowsFixedSizeDialogHint = true
  18.         },
  19.        
  20.         ui:VGroup{
  21.             ID = "root",
  22.            
  23.             -- Add your GUI elements here:
  24.             ui:HGroup{
  25.                 Weight = 6,
  26.  
  27.                 ui:Label{
  28.                     ID = "TextMsg",
  29.                     Text = msg,
  30.                     Weight = 1,
  31.                    
  32.                     WordWrap = true,
  33.                     Alignment = {
  34.                         AlignHCenter = true,
  35.                         AlignVCenter = true,
  36.                     },
  37.                  },
  38.             },
  39.             ui:HGroup{
  40.                 ui:Label{
  41.                     Weight = 4,
  42.                     ID = "LabelDummy",
  43.                 },
  44.                 ui:Button{ID = "ButtonOK", Text = "OK" },
  45.             }
  46.         }
  47.     });
  48.     win:Resize({ 400, 150 });
  49.     win:RecalcLayout();
  50.  
  51.     -- The window was closed
  52.     function win.On.ButtonOK.Clicked(ev)
  53.         disp:ExitLoop();
  54.     end
  55.  
  56.     function win.On.WinMsg.Close(ev)
  57.         disp:ExitLoop();
  58.     end
  59.  
  60.     win:Show();
  61.     disp:RunLoop();
  62.     win:Hide();
  63. end

Greetz!
Nick

User avatar
Midgardsormr
Fusionista
Posts: 936
Joined: Wed Nov 26, 2014 8:04 pm
Location: Los Angeles, CA, USA
Been thanked: 26 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#146

Post by Midgardsormr » Thu Jun 21, 2018 10:06 am

The UIWidget class has a parameter FixedSize. If you set that on your 'root' VGroup, it should set a fixed size for the window, regardless of OS. I was toying with it a couple of weeks ago and don't remember precisely how well it worked. I realized eventually that what I actually needed was simply a minimum size, for which this worked:


Code: Select all

ui:VGroup{
		    	ID = 'header',
		    	Weight = 0,
		    	ui:TextEdit{ ID = 'museLogo', ReadOnly = true, Alignment = { AlignHCenter = true, AlignTop = true, }, MinimumSize = {650, 130}, MaximumSize = {width * 2, 130}, HTML = html, },
		    	
		    },

Nick Verlinden
Posts: 8
Joined: Thu Apr 12, 2018 5:29 am

Re: Building GUIs With Fusion's UI Manager

#147

Post by Nick Verlinden » Thu Jun 21, 2018 11:42 am

Just tested this on macOS, the MS hint does not work (to be expected).
I've tried adding "FixedSize" to the VGroup, but then the dialog is still resizable, the content is just clipped (but does still stretch) when resizing bigger than the specified value. Adding it to the Widnow seems to have no effect at all.

User avatar
PeterLoveday
Fusioneer
Posts: 130
Joined: Sun Sep 14, 2014 6:09 pm
Been thanked: 2 times

Re: Building GUIs With Fusion's UI Manager

#148

Post by PeterLoveday » Thu Jun 21, 2018 6:50 pm

You can try adding FixedX = , and FixedY = , to the root level group (not the window itself), see if that works any better...

Nick Verlinden
Posts: 8
Joined: Thu Apr 12, 2018 5:29 am

Re: Building GUIs With Fusion's UI Manager

#149

Post by Nick Verlinden » Fri Jun 22, 2018 6:53 am

Setting FixedX and FixedY on the root group works, the dialog is not resizable anymore, but then it seems to ignore the resize function call, and you need to call win:RecalcLayout(); in order for the window to scale to its contents automatically.

For the record, I'm avoiding the "Geometry" setting, because I want my window to appear in the center of the Fusion/resolve window.

A couple of things i already tried but still do not allow me to specify a window size:
-Setting window type to Dialog and Tool
-Adding FixedSize = { width, height } to VGroup and Window
-Adding MinimumSize and MaximumSize works for the VGroup, but does not resize the window
-Removing win:RecalcLayout(); but that results in the layout to be incorrect.

I'm still experimenting a bit more, but it doesn't look promising other than using hacks such as adding spaces to the end of a label to make the window wider when it is automatically adjusting the size to the contents.

User avatar
SecondMan
Site Admin
Posts: 3131
Joined: Thu Jul 31, 2014 5:31 pm
Location: Vancouver, Canada
Been thanked: 35 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#150

Post by SecondMan » Fri Jun 22, 2018 8:27 am

Just out of interest, why would you not want a window to be resizable?