Building GUIs With Fusion's UI Manager

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

Re: Building GUIs With Fusion's UI Manager

#181

Post by AndrewHazelden » Mon Feb 11, 2019 8:59 am

pixelstuff wrote:
Mon Feb 11, 2019 8:33 am
I can't seem to find a solution to this and thought maybe its a bug or something else that I have installed that's causing it. The trouble is I don't know how to troubleshoot it.

Hi @pixelstuff.

When things go wrong with UI Manager there isn't a lot of ways to troubleshoot things since all users have to work with, are small fragments of details and scraps of information. :-|

If you want to see scripting functionality and API documentation improved in Resolve 15 and in Fusion Standalone 9 you need to reach out to BMD and let them know its a priority for you. The lack of official *modern* scripting documentation on features like UI Manager, Actions, and Events makes Lua and Python scripting a process of trial and error for end users that make things harder than necessary.

Tags:

User avatar
pixelstuff
Posts: 41
Joined: Sun Jul 15, 2018 11:50 am
Been thanked: 1 time

Re: Building GUIs With Fusion's UI Manager

#182

Post by pixelstuff » Mon Feb 11, 2019 9:47 am

Thanks, I'll contact them directly as its an issue with Fusion 9 and the same happens in Resolve 15, maybe they can track the cause of the problem down :)

User avatar
miaz3
Fusioneer
Posts: 209
Joined: Sat Jan 03, 2015 1:43 am
Location: Angoulême / France
Been thanked: 2 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#183

Post by miaz3 » Fri Mar 01, 2019 12:48 pm

Thanks @PeterLoveday for the tab bar, didn't know !
Thanks @AndrewHazelden i'didnt' know it...i made a func to use uuid...i will integrate it directly into my script :)
  1. function uuid()
  2.     math.randomseed(os.time())
  3.     local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
  4.     return string.gsub(template, '[xy]', function (c)
  5.         local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
  6.         return string.format('%x', v)
  7.     end)
  8. end
Added in 36 minutes 4 seconds:
I thought, we could call (since bmd.scriptapp ()) another module that 'Fusion', ip, timeout, uuid, subtype ?

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

Re: Building GUIs With Fusion's UI Manager

#184

Post by AndrewHazelden » Mon Apr 08, 2019 6:55 am

pixelstuff wrote:
Sun Feb 03, 2019 4:14 am
A problem I'm running into is for some reason the action detection stops(see gif) after a period of time or number of iterations(both time and inputs). Would you have any idea what could possibly be causing this, as I also checked the UI Manager "List input control names" examples in Reactor and it seems to do the same in Win10 and Mac OSX.

The console "time changed" is within the function below.

Code: Select all

ui:AddNotify('Time_Set', comp)

function disp.On.Time_Set(ev)
	print('time changed')
end


There is a possibility that garbage collection in Lua is disposing of the AddNotify action after a while. If you store the pointer returned by the ui:AddNotify() function in a variable it might potentially solve your issue:

Code: Select all

notify = ui:AddNotify('Time_Set', comp)

function disp.On.Time_Set(ev)
	print('time changed')
end

User avatar
pixelstuff
Posts: 41
Joined: Sun Jul 15, 2018 11:50 am
Been thanked: 1 time

Re: Building GUIs With Fusion's UI Manager

#185

Post by pixelstuff » Sun Apr 14, 2019 2:45 pm

thanks @AndrewHazelden BMD confirmed this as a bug, and unfortunately it's still there currently with 16, but hopefully it will be fixed soon.

That makes sense what you have suggested I'll give it a try :)

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

Fuskin Button Toolbar GUI

#186

Post by AndrewHazelden » Fri Aug 16, 2019 10:57 am

The Fuskin Button Toolbar GUI.lua script example has been added to the "UI Manager Lua & Python Examples" atom package in Reactor.

This is a Fusion 16/Resolve 16 compatible script that extracts a series of image resources from the zipped Fuskin file and generates a new UI Manager based toolbar GUI. This script uses the new "ZipFile()" functionality that is only present in Fu16+ Lua scripting.

This script was previously mentioned on the WSL thread "Fetching an image from the .fuskin file via script?" back on 2019-05-06.

Screenshot

FuskinButtonToolbarGUI.png
You do not have the required permissions to view the files attached to this post.

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

Tree Icons Comp Browser

#187

Post by AndrewHazelden » Thu Aug 22, 2019 4:57 pm

Fusion 16 granted a UI Manager centric wish list item "ui:Icon Support in a UI Manager ui:Tree Layout" that I had requested back in 2018. This feature allows for custom PNG icons to be added to a list view, or for a photo-browser like GUI to be made with preview thumbnail images. :banana:

Tree Icons Comp Browser

Tree Icon Comp Browser.png
Here is a Comp Browser demo that has little tiny Fusion icons added next to each comp file in the uiTree view layout.

This script can be used as a Fusion "Comp Browser" window that displays a list of currently open Fusion .comp files, and the rows list summary details about each comp. Double clicking on a row in the Comp Browser ui:Tree view will open the comp file's parent folder in a desktop folder browsing window.

This script requires Fusion Standalone 16 in order to work correctly as the ability to add ui:Icon resources to a ui:Tree was added to the UI Manager library in this version.
Code: [Select all] [Expand/Collapse] [Download] (Tree Icon Comp Browser.lua)
  1. --[[--
  2. ----------------------------------------------------------------------------
  3. Comp Browser for Fusion - v1.0 2019-08-22 8.33 PM
  4. by Andrew Hazelden <andrew@andrewhazelden.com>
  5. www.andrewhazelden.com
  6. -- ----------------------------------------------------------------------------
  7.  
  8. This script is from the Reactor "UI Manager Lua & Python Examples" atom package.
  9.  
  10. It is primarily designed as a code demo for how a ui:Icon PNG image resource can be added to a ui:Tree.
  11.  
  12. This script can be used as a Fusion "Comp Browser" window that displays a list of currently open Fusion .comp files, and the rows list summary details about each comp. Double clicking on a row in the Comp Browser ui:Tree view will open the comp file's parent folder in a desktop folder browsing window.
  13.  
  14. This script requires Fusion Standalone 16 in order to work correctly as the ability to add ui:Icon resources to a ui:Tree was added to the UI Manager library in this version.
  15.  
  16. --]]--
  17.  
  18.  
  19. -- Find out the current directory from a file path
  20. -- Example: print(dirname('/Volumes/Media/image.0000.exr'))
  21. function dirname(filename)
  22.     return filename:match('(.*' .. osSeparator .. ')')
  23. end
  24.  
  25. -- Show the ui:Tree View
  26. function CompBrowser()
  27.     local ui = fu.UIManager
  28.     local disp = bmd.UIDispatcher(ui)
  29.     local width,height = 1920,600
  30.  
  31.     win = disp:AddWindow({
  32.         ID = 'CompBrowserWin',
  33.         TargetID = 'CompBrowserWin',
  34.         WindowTitle = 'Comp Browser',
  35.         Geometry = {0, 100, width, height},
  36.         Spacing = 0,
  37.  
  38.         ui:VGroup{
  39.             ID = 'root',
  40.             ui:Tree{
  41.                 ID = 'Tree',
  42.                 SortingEnabled = true,
  43.                 Events = {
  44.                     ItemDoubleClicked = true,
  45.                     ItemClicked = true,
  46.                 },
  47.             },
  48.         },
  49.     })
  50.  
  51.     -- The window was closed
  52.     function win.On.CompBrowserWin.Close(ev)
  53.         disp:ExitLoop()
  54.     end
  55.  
  56.     -- Add your GUI element based event functions here:
  57.     itm = win:GetItems()
  58.  
  59.     -- Add a header row.
  60.     hdr = itm.Tree:NewItem()
  61.     hdr.Text[0] = 'Comp Name'
  62.     hdr.Text[1] = 'Media Nodes'
  63.     hdr.Text[2] = 'Global Range'
  64.     hdr.Text[3] = 'Render Range'
  65.     hdr.Text[4] = 'Format Name'
  66.     hdr.Text[5] = 'Frame Size'
  67.     hdr.Text[6] = 'Frame Rate'
  68.     hdr.Text[7] = 'HiQ'
  69.     hdr.Text[8] = 'Rendering'
  70.     hdr.Text[9] = 'Filepath'
  71.  
  72.     itm.Tree:SetHeaderItem(hdr)
  73.  
  74.     -- Number of columns in the Tree list
  75.     itm.Tree.ColumnCount = 10
  76.  
  77.     -- Resize the Columns
  78.     itm.Tree.ColumnWidth[0] = 320
  79.     itm.Tree.ColumnWidth[1] = 90
  80.     itm.Tree.ColumnWidth[2] = 90
  81.     itm.Tree.ColumnWidth[3] = 90
  82.     itm.Tree.ColumnWidth[4] = 182
  83.     itm.Tree.ColumnWidth[5] = 100
  84.     itm.Tree.ColumnWidth[6] = 70
  85.     itm.Tree.ColumnWidth[7] = 50
  86.     itm.Tree.ColumnWidth[8] = 65
  87.     itm.Tree.ColumnWidth[9] = 600
  88.  
  89.     -- Change the sorting order of the tree
  90.     itm.Tree:SortByColumn(0, "AscendingOrder")
  91.  
  92.     -- Create a table based upon the open Fusion composites
  93.     local compList = fu:GetCompList()
  94.     for row = 1, table.getn(compList) do
  95.         -- Set cmp to the pointer of the current composite
  96.         cmp = compList[row]
  97.  
  98.         -- Add a new row entry to the list
  99.         itRow = itm.Tree:NewItem();
  100.    
  101.         -- Add an image resource to the cell
  102.         -- Make sure this is excluded from Fusion 9 since the Icon support in a tree view was added in v16.
  103.         if fu:GetVersion() and fu:GetVersion()[1] and fu:GetVersion()[1] >= 16 then
  104.             itRow.Icon[0] = ui:Icon{File = 'Scripts:/Comp/UI Manager/fusion-logo.png'}
  105.         end
  106.        
  107.         -- The Composite Tab name (comp base filename)
  108.         itRow.Text[0] = string.format('%s', tostring(cmp:GetAttrs()['COMPS_Name']))
  109.    
  110.         -- Node count
  111.         -- Should the selected nodes be listed? (Otherwise all loader/saver nodes will be listed from the comp)
  112.         --listOnlySelectedNodes = true
  113.         listOnlySelectedNodes = false
  114.  
  115.         local toollist1 = cmp:GetToolList(listOnlySelectedNodes, 'Loader')
  116.         local toollist2 = cmp:GetToolList(listOnlySelectedNodes, 'Saver')
  117.         local toollist3 = cmp:GetToolList(listOnlySelectedNodes, 'SurfaceFBXMesh')
  118.         local toollist4 = cmp:GetToolList(listOnlySelectedNodes, 'SurfaceAlembicMesh')
  119.  
  120.         -- Scan the comp to check how many media nodes are present
  121.         local totalLoaders = table.getn(toollist1)
  122.         local totalSavers = table.getn(toollist2)
  123.         local totalFBX = table.getn(toollist3)
  124.         local totalAlembic = table.getn(toollist4)
  125.    
  126.         -- Add up how many media nodes are present
  127.         local totalNodes = totalLoaders + totalSavers + totalFBX + totalAlembic
  128.         itRow.Text[1] = tostring(totalNodes)
  129.  
  130.         -- Timeline Frame Range
  131.         itRow.Text[2] = tostring(cmp:GetAttrs().COMPN_GlobalStart) .. '-' .. tostring(cmp:GetAttrs().COMPN_GlobalEnd)
  132.         itRow.Text[3] = tostring(cmp:GetAttrs().COMPN_RenderStart) .. '-' .. tostring(cmp:GetAttrs().COMPN_RenderEnd)
  133.  
  134.         -- Read the comp frame format settings
  135.         local compPrefs = cmp:GetPrefs("Comp.FrameFormat")
  136.  
  137.         -- Format Name
  138.         itRow.Text[4] = tostring(compPrefs.Name)
  139.  
  140.         -- Frame Size
  141.         itRow.Text[5] = tostring(compPrefs.Width) .. 'x' .. tostring(compPrefs.Height) .. ' px'
  142.  
  143.         -- Frame Rate
  144.         itRow.Text[6] = tostring(compPrefs.Rate) .. ' fps'
  145.  
  146.         -- HiQ High Quality Mode
  147.         itRow.Text[7] = tostring(cmp:GetAttrs().COMPB_HiQ)
  148.  
  149.         -- Render Status
  150.         itRow.Text[8] = tostring(cmp:GetAttrs().COMPB_Rendering)
  151.  
  152.         -- The Composite absolute filename
  153.         local filepath = cmp:MapPath(cmp:GetAttrs()['COMPS_FileName'])
  154.         if filepath == '' or not filepath then
  155.             filepath = '<Unsaved>'
  156.         end
  157.         itRow.Text[9] = tostring(filepath)
  158.  
  159.  
  160.         itm.Tree:AddTopLevelItem(itRow)
  161.     end
  162.  
  163.     -- A Tree view row was clicked on
  164.     function win.On.Tree.ItemClicked(ev)
  165.         print('[Single Clicked] ' .. tostring(ev.item.Text[9]))
  166.     end
  167.  
  168.     -- A Tree view row was double clicked on
  169.     function win.On.Tree.ItemDoubleClicked(ev)
  170.         -- Grab the absolute comp filepath
  171.         local compPath = dirname(tostring(ev.item.Text[9] or ''))
  172.         print('[Double Clicked] ' .. tostring(compPath))
  173.  
  174.         -- Open the comp file's parent folder in a desktop folder browsing window
  175.         if bmd.direxists(compPath) == true then
  176.             bmd.openfileexternal('Open', compPath)
  177.         end
  178.     end
  179.  
  180.     -- The app:AddConfig() command will capture the "Control + W" or "Control + F4" hotkeys so they will close the window instead of closing the foreground composite.
  181.     app:AddConfig("CompBrowserWin", {
  182.         Target
  183.         {
  184.             ID = "CompBrowserWin",
  185.         },
  186.  
  187.         Hotkeys
  188.         {
  189.             Target = "CompBrowserWin",
  190.             Defaults = true,
  191.  
  192.             CONTROL_W = "Execute{ cmd = [[ app.UIManager:QueueEvent(obj, 'Close', {}) ]] }",
  193.             CONTROL_F4 = "Execute{ cmd = [[ app.UIManager:QueueEvent(obj, 'Close', {}) ]] }",
  194.         },
  195.     })
  196.  
  197.     win:Show()
  198.     disp:RunLoop()
  199.     win:Hide()
  200. end
  201.  
  202.  
  203. -- Find out the current operating system platform. The platform local variable should be set to either "Windows", "Mac", or "Linux".
  204. local platform = (FuPLATFORM_WINDOWS and 'Windows') or (FuPLATFORM_MAC and 'Mac') or (FuPLATFORM_LINUX and 'Linux')
  205.  
  206. -- Add the platform specific folder slash character
  207. osSeparator = package.config:sub(1,1)
  208.  
  209. -- Show the ui:Tree View
  210. CompBrowser()
  211.  
  212. -- End of the script
  213. print('[Done]')
  214.  

As a quick summary, the ui:Icon resource was added to the ui:Tree item using the following snippet of code:

(The Fusion version check ensures that Fusion 16+ was found to avoid causing errors when the code is run in either Fusion 9, or Resolve 15.)

Code: Select all

		-- Add an image resource to the cell
		-- Make sure this is excluded from Fusion 9 since the Icon support in a tree view was added in v16.
		if fu:GetVersion() and fu:GetVersion()[1] and fu:GetVersion()[1] >= 16 then
			itRow.Icon[0] = ui:Icon{File = 'Scripts:/Comp/UI Manager/fusion-logo.png'}
		end
You do not have the required permissions to view the files attached to this post.

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

Running Python Code in an Event

#188

Post by AndrewHazelden » Fri Sep 20, 2019 8:16 am

@bryanfordney recently asked if Python scripting was an option for events and callbacks. A sharp-eyed fact-checker reminded me this morning that I should always double-check things... Ahh, the things you learn. :)

Here are several approaches to create Events in Fusion that will allow you to run your own Python code when the Event is triggered. This can be handy if you are a TD that feels the need to write your Fusion based .fu code in Python.

Update your UI Manager Examples Atom Package

Reactor Atom Update.png

If you have Reactor installed, and update your "UI Manager Lua & Python Examples" atom package to version 2, you will find new Event examples in the Reactor:/Deploy/Config/UI Manager/ folder named EventPythonNative.fu.zip, EventPythonRunScript.zip, and EventPythonExecute.fu.zip.

To use one of the Python Event examples, you simply need to unzip one of these files in-place, inside the Config folder, and then restart Fusion. When you select nodes in the Node view you will see a message printed in the Console window:

Events Example.png

EventPythonNative Example

This example shows a Python native way to execute code inside an Event. No Lua code is involved. This is done with a .fu file-based Event{} entry that intercepts the "Comp_Activate_Tool" action by appending our own Python code snippet that is specified with the tag Language = "Python2",.

EventPythonNative.png

EventPythonRunScript Example

The EventPythonRunScript.zip example provides a .fu file and a .py script. It shows a way to execute an external Python script inside an Event that was created using Lua. This is done with a .fu file based Event{} entry that intercepts the native "Comp_Activate_Tool" action that will run our Python script via "comp:RunScript()".

When you select a node in the Nodes view, the active tool's name is printed in the Console window via a Python script named PythonRunScript.py. The Python script is able to access the "comp" object and its parameters.

EventPythonRunScript.png

EventPythonExecute Example

The EventPythonExecute.fu.zip example provides a .fu file that shows a way to execute a block of Python code inside an Event that was created using Lua. This is done with a .fu file-based Event{} entry that intercepts the native "Comp_Activate_Tool" action by appending our own custom Python code snippet that runs via comp:Execute().

This approach could be handy if you have existing Lua code in other parts of your .fu file and you want to add a little bit of Python code to one specific Event.

By adding "!Py:" to the start of the string passed to comp:Execute() it tells the interpreter to process the code using the default built-in Python interpreter that is found on your system.

You can specify if you want to have the Python code run via Python 2 using "!Py2:", or via Python 3 using "!Py3:" on the "cmp:Execute()" line of the code below.

When you select a node in the Nodes view, the active tool's name is printed in the Console window via an inline Python code chunk. The Python code is able to access the "comp" object and its parameters.

EventPythonExecute.png
You do not have the required permissions to view the files attached to this post.
Last edited by AndrewHazelden on Sat Sep 21, 2019 5:22 am, edited 3 times in total.

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

.fu Based Contextual Menus - Python Print Attributes

#189

Post by AndrewHazelden » Fri Sep 20, 2019 10:27 pm

This Menu/Action example adds right-click based contextual menu entries named "Fusion Attributes", "Comp Attributes", and "Tool Attributes" to the Nodes view area. This is implemented using Python scripting in the .fu file's Action entries.

Contextual Menu Screenshots

Right click Closeup.png
Contextual Menu Entries.png

Menu Item Outputs

When you select a node in the Nodes view and right-click, the new "Tool Attributes" contextual menu entry allows you to see details like the active Node's name, the Tool's RegistryID, and more in the Fusion Console view:

Code: Select all

'[Tool Attributes]'
{'TOOLB_CacheToDisk': False,
 'TOOLB_CtrlWZoom': False,
 'TOOLB_HoldOutput': False,
 'TOOLB_Locked': False,
 'TOOLB_NameSet': False,
 'TOOLB_PassThrough': False,
 'TOOLB_Selected': True,
 'TOOLB_ShowControls': True,
 'TOOLB_Visible': True,
 'TOOLI_ID': 41.0,
 'TOOLI_Number_o_Inputs': 1.0,
 'TOOLNT_EnabledRegion_End': {1.0: 1000000000.0},
 'TOOLNT_EnabledRegion_Start': {1.0: -1000000000.0},
 'TOOLNT_Region_End': {1.0: 999999999.9999},
 'TOOLNT_Region_Start': {1.0: 0.0},
 'TOOLN_LastFrameTime': 0.0,
 'TOOLS_Name': 'Equirectangular2Fisheye',
 'TOOLS_RegID': 'GroupOperator'}

The new "Comp Attributes" contextual menu prints out the composition object's details:

Code: Select all

'[Comp Attributes]'
{'COMPB_HiQ': True,
 'COMPB_Locked': False,
 'COMPB_LoopPlay': True,
 'COMPB_Modified': True,
 'COMPB_MotionBlur': True,
 'COMPB_Proxy': False,
 'COMPB_Rendering': False,
 'COMPH_ActiveTool': <PyRemoteObject object at 0x5a8f71f8>,
 'COMPI_RenderFlags': 131072.0,
 'COMPI_RenderStep': 1.0,
 'COMPN_AudioOffset': 0.0,
 'COMPN_AverageFrameTime': 0.0,
 'COMPN_CurrentTime': 0.0,
 'COMPN_ElapsedTime': 0.0,
 'COMPN_GlobalEnd': 1000.0,
 'COMPN_GlobalStart': 0.0,
 'COMPN_LastFrameRendered': -2000000000.0,
 'COMPN_LastFrameTime': 0.0,
 'COMPN_RenderEnd': 1000.0,
 'COMPN_RenderEndTime': 1000.0,
 'COMPN_RenderStart': 0.0,
 'COMPN_RenderStartTime': 0.0,
 'COMPN_TimeRemaining': 0.0,
 'COMPS_FileName': '/Users/andrew/Desktop/Composition1.comp',
 'COMPS_LoopMode': 'loop',
 'COMPS_Name': 'Composition1.comp'}

And the new "Fusion Attributes" contextual menu prints out the fusion/fu/app object details:

Code: Select all

'[Fusion Attributes]'
{'FUSIONB_IsManager': False,
 'FUSIONB_IsRenderNode': False,
 'FUSIONB_IsResolve': False,
 'FUSIONH_CurrentComp': <PyRemoteObject object at 0x5a8f7210>,
 'FUSIONI_NumProcessors': 8.0,
 'FUSIONI_PhysicalRAMFreeMB': 10256.0,
 'FUSIONI_PhysicalRAMTotalMB': 16384.0,
 'FUSIONI_SerialHi': 'Redacted-by-Andrew',
 'FUSIONI_SerialLo': 0.0,
 'FUSIONI_VersionHi': 1048577.0,
 'FUSIONI_VersionLo': 7.0,
 'FUSIONI_VirtualRAMTotalMB': 16384.0,
 'FUSIONI_VirtualRAMUsedMB': 6127.0,
 'FUSIONS_FileName': '/Applications/Blackmagic Fusion 16/Fusion.app/Contents/MacOS/Fusion',
 'FUSIONS_GLDevice': 'AMD Radeon R9 M370X OpenGL Engine',
 'FUSIONS_GLVendor': 'ATI Technologies Inc.',
 'FUSIONS_GLVersion': '2.1 ATI-1.68.23',
 'FUSIONS_MachineType': 'IA32',
 'FUSIONS_Version': '16.1'}

Download the .fu File

The ContextualMenuPythonPrintAttributes.fu file goes in your Config:/ PathMap folder.

If you've already got the UI Manager Examples atom package installed in Reactor you can update the package to the latest version, and you will find a zipped copy of this .fu file in your Reactor:/Deploy/Config/UI Manager/ Folder.
Code: [Select all] [Expand/Collapse] [Download] (ContextualMenuPythonPrintAttributes.fu)
  1. --[[--
  2. Contextual Menu - Python Print Attributes - 2019-09-21
  3. by Andrew Hazelden <andrew@andrewhazelden.com>
  4. www.andrewhazelden.com
  5.  
  6. This Menu/Action adds right-click based contextual menu entries named "Fusion Attributes", "Comp Attributes", and "Tool Attributes" to the Nodes view area. This is implemented using Python scripting in the .fu file's Action entries.
  7.  
  8. When you select a node in the Nodes view and right-click, the "Tool Attributes" contextual menu entry allows you to see details like the active Node's name, the Tool's RegistryID, and more.
  9.  
  10. -------------------------------------------------
  11.  
  12. The default Target value of "FlowView" is used to add your menu entry to the Nodes view area.
  13.  
  14. If you want to change the target zone where the Menu entries are added you can edit the line:
  15. Target = "FlowView",
  16.  
  17. And then change the Target to another value like the "Tools_RegID" value of an individual node/fuse/MacroOperator/GroupOperator so your contextual menu entry appears in the Inspector view when only that node type is selected. This can be done by entering a value such as "Camera3D" if you want your contextual menu to show up when a Camera3D node is active in the Inspector window.
  18.  
  19. If you wanted the contextual menu to show up in a specific view like the Fusion 3D viewer window area, a Target value of "GL3DViewer" will push the menu into the Fusion 3D workspace view's right-clickable contextual menu. (This Target is separate from the 2D image viewer area.)
  20.  
  21. A Target value of "Composition" will add your menu entry to the individual "Composite" tabs that list each of the open Comp names in Fusion. The Compositon tab is the horizontal bar of tabs located  that you can right-click on. It's positioned just under the Fusion main menu bar area. (There is a slight contextual menu rendering bug in Fusion 16 that is visible when using this target. You will see your new menu entries are added twice to the list.)
  22.  
  23. -------------------------------------------------
  24.  
  25. The Lua based code chunk below will list all of the active Target IDs you can possibly choose from in Fusion: (Not all of them are valid for use as contextual menu locations since it is an unfiltered raw dump from the Fusion registry)
  26.  
  27. -- Scan Target IDs
  28. targetIDList = fu.ActionManager:GetTargets()
  29.  
  30. -- Count the total number of targetIDs
  31. targetCount = 0
  32. for i, target in ipairs(targetIDList) do
  33.     print(target.ID)
  34.     targetCount = targetCount + 1
  35. end
  36. print('[' .. targetCount .. ' Target IDs Found]')
  37.  
  38. --]]--
  39. {
  40.   Language = "Python2",
  41.  
  42.   Action{
  43.     ID = "Print_Fusion_Attributes",
  44.     Category = "Utilities",
  45.     Name = "Fusion Attributes",
  46.  
  47.     Targets = {
  48.       Composition = {
  49.         Execute = _Python [=[
  50. from pprint import pprint
  51.  
  52. # Print the current Fusion program attributes
  53. pprint("[Fusion Attributes]")
  54. pprint(fu.GetAttrs())
  55. print("\n")
  56.         ]=],
  57.       },
  58.     },
  59.   },
  60.  
  61.   Action{
  62.     ID = "Print_Comp_Attributes",
  63.     Category = "Utilities",
  64.     Name = "Comp Attributes",
  65.  
  66.     Targets = {
  67.       Composition = {
  68.         Execute = _Python [=[
  69. from pprint import pprint
  70.  
  71. # Get the composition object
  72. # comp = obj.Comp()
  73.  
  74. # Get the composition object (alternative)
  75. comp = app.GetAttrs()["FUSIONH_CurrentComp"]
  76.  
  77. # Print the current composite attributes
  78. pprint("[Comp Attributes]")
  79. pprint(comp.GetAttrs())
  80. print("\n")
  81.         ]=],
  82.       },
  83.     },
  84.   },
  85.  
  86.   Action{
  87.     ID = "Print_Tool_Attributes",
  88.     Category = "Utilities",
  89.     Name = "Tool Attributes",
  90.  
  91.     Targets = {
  92.       Composition = {
  93.         Execute = _Python [=[
  94. from pprint import pprint
  95.  
  96. # Get the composition object
  97. # comp = obj.Comp()
  98.  
  99. # Get the composition object (alternative)
  100. comp = app.GetAttrs()["FUSIONH_CurrentComp"]
  101.  
  102. # Get the active node selection
  103. selection = 'None' if comp.ActiveTool is None else comp.ActiveTool.GetAttrs()
  104.  
  105. # Print the current tool attributes
  106. pprint("[Tool Attributes]")
  107. pprint(selection)
  108. print("\n")
  109.         ]=],
  110.       },
  111.     },
  112.   },
  113.  
  114.   Menus{
  115.     -- Add the menu entries to the Node view's right-click based contextual menus.
  116.     Target = "FlowView",
  117.    
  118.     -- Add the menu entries to the Fusion's 3D view's right-click based contextual menus.
  119.     -- Target = "GL3DViewer",
  120.    
  121.     -- Add the menu entries to the Composition tabs's right-click based contextual menus.
  122.     -- Note: The entries will be listed twice in this Target due to a Fusion 16 bug.
  123.     -- Target = "Composition",
  124.  
  125.     Append{
  126.       "_",
  127.       "Print_Fusion_Attributes{}",
  128.       "Print_Comp_Attributes{}",
  129.       "Print_Tool_Attributes{}",
  130.     },
  131.   },
  132. }
  133.  

Menu Targets

The default Target value of "FlowView" is used to add your menu entry to the Nodes view area. If you want to change the target zone where the Menu entries are added you can edit the line:
Target = "FlowView",


And then change the Target to another value like the "Tools_RegID" value of an individual node/fuse/MacroOperator/GroupOperator so your contextual menu entry appears in the Inspector view when only that node type is selected. This can be done by entering a value such as "Camera3D" if you want your contextual menu to show up when a Camera3D node is active in the Inspector window.

Camera3D Contextual Menu.png

If you wanted the contextual menu to show up in a specific view like the Fusion 3D viewer window area, a Target value of "GL3DViewer" will push the menu into the Fusion 3D workspace view's right-clickable contextual menu. (This Target is separate from the 2D image viewer area.)

GL3DViewer Target.png

A Target value of "Composition" will add your menu entry to the individual "Composite" tabs that list each of the open Comp names in Fusion. The Compositon tab is the horizontal bar of tabs located that you can right-click on. It's positioned just under the Fusion main menu bar area. (There is a slight contextual menu rendering bug in Fusion 16 that is visible when using this target. You will see your new menu entries are added twice to the list.)

Composition Target.png

Scanning for Menu Target IDs

The Lua based code chunk below will list all of the active Target IDs you can possibly choose from in Fusion:
(Not all of them are valid for use as contextual menu locations since it is an unfiltered raw dump from the Fusion registry)
Code: [Select all] [Expand/Collapse] [Download] (ScanTargetIDs.lua)
  1. -- Scan Target IDs
  2. targetIDList = fu.ActionManager:GetTargets()
  3.  
  4. -- Count the total number of targetIDs
  5. targetCount = 0
  6. for i, target in ipairs(targetIDList) do
  7.     print(target.ID)
  8.     targetCount = targetCount + 1
  9. end
  10. print('[' .. targetCount .. ' Target IDs Found]')
You do not have the required permissions to view the files attached to this post.

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

Common Variables Found in a .fu Event Execute Scope

#190

Post by AndrewHazelden » Sat Sep 21, 2019 7:00 am

This post has a Python based example that shows the common variables like args that are present in to your .fu files' Action/Event Execute entries.

If your Event was run in the scope of "Composition", which is what the Nodes view in Fusion is called, the args variable would return a Python dict with information about the active tool like:

Code: Select all

{'tool': <PyRemoteObject object at 0x60aad1c8>}
or args might return a dict with both the active tool, and the previously active tool listed:

Code: Select all

{'prev': <PyRemoteObject object at 0x626551f8>,
'tool': <PyRemoteObject object at 0x626551e0>}

Download the .fu File

Code: [Select all] [Expand/Collapse] [Download] (EventPythonPrintArgs.fu)
  1. --[[--
  2. Printing Python Args in an Event - 2019-09-21
  3. by Andrew Hazelden <andrew@andrewhazelden.com>
  4. www.andrewhazelden.com
  5.  
  6. Use Python to list the common variables that are found in an Event's "Execute" scope when you select a node in the Nodes view in Fusion.
  7.  
  8. The Console window output looks like:
  9.  
  10. ---------------------------------
  11.  
  12. '[self Default]'
  13.  
  14.  
  15. '[rets]'
  16. {}
  17.  
  18.  
  19. '[ctx Attributes]'
  20. <PyRemoteObject object at 0x5880f1b0>
  21.  
  22.  
  23. '[args Attributes]'
  24. {'prev': <PyRemoteObject object at 0x5880f258>,
  25.  'tool': <PyRemoteObject object at 0x5880f240>}
  26.  
  27.  
  28. '[args.tool Attributes]'
  29. {'TOOLBT_AltClip_IsMultiFrame': {1.0: False},
  30.  'TOOLBT_Clip_IsMultiFrame': {1.0: False},
  31.  'TOOLBT_Clip_IsPreviewSaver': {1.0: False},
  32.  'TOOLBT_Clip_Loop': {1.0: False},
  33.  'TOOLBT_Clip_Reverse': {1.0: False},
  34.  'TOOLBT_Clip_Saving': {1.0: False},
  35.  'TOOLB_CacheToDisk': False,
  36.  'TOOLB_CtrlWZoom': True,
  37.  'TOOLB_HoldOutput': False,
  38.  'TOOLB_Locked': False,
  39.  'TOOLB_NameSet': False,
  40.  'TOOLB_PassThrough': False,
  41.  'TOOLB_Selected': True,
  42.  'TOOLB_ShowControls': False,
  43.  'TOOLB_Visible': True,
  44.  'TOOLIT_AltClip_Height': {1.0: 0.0},
  45.  'TOOLIT_AltClip_Length': {1.0: 1.0},
  46.  'TOOLIT_AltClip_StartFrame': {1.0: 4294967295.0},
  47.  'TOOLIT_AltClip_Width': {1.0: 0.0},
  48.  'TOOLIT_Clip_AspectMode': {1.0: 0.0},
  49.  'TOOLIT_Clip_ExtendFirst': {1.0: 0.0},
  50.  'TOOLIT_Clip_ExtendLast': {1.0: 0.0},
  51.  'TOOLIT_Clip_Height': {1.0: 1920.0},
  52.  'TOOLIT_Clip_ImportMode': {1.0: 0.0},
  53.  'TOOLIT_Clip_InitialFrame': {1.0: 4294967295.0},
  54.  'TOOLIT_Clip_Length': {1.0: 1.0},
  55.  'TOOLIT_Clip_PullOffset': {1.0: 0.0},
  56.  'TOOLIT_Clip_StartFrame': {1.0: 4294967295.0},
  57.  'TOOLIT_Clip_TimeCode': {1.0: 0.0},
  58.  'TOOLIT_Clip_TrimIn': {1.0: 0.0},
  59.  'TOOLIT_Clip_TrimOut': {1.0: 0.0},
  60.  'TOOLIT_Clip_Width': {1.0: 3840.0},
  61.  'TOOLI_ID': 1.0,
  62.  'TOOLI_ImageDepth': 5.0,
  63.  'TOOLI_ImageField': -1.0,
  64.  'TOOLI_ImageHeight': 1920.0,
  65.  'TOOLI_ImageWidth': 3840.0,
  66.  'TOOLI_Number_o_Inputs': 0.0,
  67.  'TOOLNT_Clip_End': {1.0: 0.0},
  68.  'TOOLNT_Clip_Start': {1.0: 0.0},
  69.  'TOOLNT_EnabledRegion_End': {1.0: 1000000000.0},
  70.  'TOOLNT_EnabledRegion_Start': {1.0: -1000000000.0},
  71.  'TOOLNT_Region_End': {1.0: 999999999.9999},
  72.  'TOOLNT_Region_Start': {1.0: 0.0},
  73.  'TOOLN_ImageAspectX': 1.0,
  74.  'TOOLN_ImageAspectY': 1.0,
  75.  'TOOLN_LastFrameTime': 0.07738699999999987,
  76.  'TOOLST_AltClip_FormatID': {},
  77.  'TOOLST_AltClip_FormatName': {},
  78.  'TOOLST_AltClip_Name': {1.0: ''},
  79.  'TOOLST_Clip_FormatID': {1.0: 'JpegFormat'},
  80.  'TOOLST_Clip_FormatName': {1.0: 'JpegFormat'},
  81.  'TOOLST_Clip_KeyCode': {1.0: ''},
  82.  'TOOLST_Clip_Name': {1.0: 'Reactor:/Deploy/Macros/KartaVR/Images/latlong_wide_ar.jpg'},
  83.  'TOOLS_Name': 'Loader1',
  84.  'TOOLS_RegID': 'Loader'}
  85.  
  86.  
  87. '[args.prev Attributes]'
  88. {'TOOLB_CacheToDisk': False,
  89.  'TOOLB_CtrlWZoom': False,
  90.  'TOOLB_HoldOutput': False,
  91.  'TOOLB_Locked': False,
  92.  'TOOLB_NameSet': False,
  93.  'TOOLB_PassThrough': False,
  94.  'TOOLB_Selected': True,
  95.  'TOOLB_ShowControls': True,
  96.  'TOOLB_Visible': True,
  97.  'TOOLI_ID': 2.0,
  98.  'TOOLI_Number_o_Inputs': 1.0,
  99.  'TOOLNT_EnabledRegion_End': {1.0: 1000000000.0},
  100.  'TOOLNT_EnabledRegion_Start': {1.0: -1000000000.0},
  101.  'TOOLNT_Region_End': {1.0: 999999999.9999},
  102.  'TOOLNT_Region_Start': {1.0: 0.0},
  103.  'TOOLN_LastFrameTime': 0.0,
  104.  'TOOLS_Name': 'Equirectangular2Fisheye',
  105.  'TOOLS_RegID': 'GroupOperator'}
  106.  
  107.  
  108. ---------------------------------
  109.  
  110. --]]--
  111. {
  112.         Language = "Python2",
  113.      
  114.         Event {
  115.                 -- Add a new event that intercepts the Action
  116.                 Action = "Comp_Activate_Tool",
  117.                 Targets = {
  118.                         Composition = {
  119.                                 Execute = _Python [=[
  120. from pprint import pprint
  121.  
  122. pprint("[self Default]")
  123. rets = self.Default(ctx, args)
  124. print("\n")
  125.  
  126.  
  127. pprint("[rets]")
  128. pprint(rets)
  129. print("\n")
  130.  
  131.  
  132. pprint("[ctx Attributes]")
  133. pprint(ctx)
  134. print("\n")
  135.  
  136.  
  137. pprint("[args Attributes]")
  138. pprint(args)
  139. print("\n")
  140.  
  141.  
  142. pprint("[args.tool Attributes]")
  143. if "tool" in args:
  144.         tool = args["tool"].GetAttrs()
  145. else:
  146.         tool = "None"
  147.  
  148. pprint(tool)
  149. print("\n")
  150.  
  151.  
  152. pprint("[args.prev Attributes]")
  153. if "prev" in args:
  154.         prev = args["prev"].GetAttrs()
  155. else:
  156.         prev = "None"
  157.  
  158. pprint(prev)
  159. print("\n")
  160.  
  161. print("---------------------------------\n")
  162. ]=],
  163.                         },
  164.                 },
  165.         },
  166. }
  167.  

Example Console Output

Code: Select all

---------------------------------
 
'[self Default]'
 
 
'[rets]'
{}
 
 
'[ctx Attributes]'
<PyRemoteObject object at 0x5880f1b0>
 
 
'[args Attributes]'
{'prev': <PyRemoteObject object at 0x5880f258>,
 'tool': <PyRemoteObject object at 0x5880f240>}
 
 
'[args.tool Attributes]'
{'TOOLBT_AltClip_IsMultiFrame': {1.0: False},
 'TOOLBT_Clip_IsMultiFrame': {1.0: False},
 'TOOLBT_Clip_IsPreviewSaver': {1.0: False},
 'TOOLBT_Clip_Loop': {1.0: False},
 'TOOLBT_Clip_Reverse': {1.0: False},
 'TOOLBT_Clip_Saving': {1.0: False},
 'TOOLB_CacheToDisk': False,
 'TOOLB_CtrlWZoom': True,
 'TOOLB_HoldOutput': False,
 'TOOLB_Locked': False,
 'TOOLB_NameSet': False,
 'TOOLB_PassThrough': False,
 'TOOLB_Selected': True,
 'TOOLB_ShowControls': False,
 'TOOLB_Visible': True,
 'TOOLIT_AltClip_Height': {1.0: 0.0},
 'TOOLIT_AltClip_Length': {1.0: 1.0},
 'TOOLIT_AltClip_StartFrame': {1.0: 4294967295.0},
 'TOOLIT_AltClip_Width': {1.0: 0.0},
 'TOOLIT_Clip_AspectMode': {1.0: 0.0},
 'TOOLIT_Clip_ExtendFirst': {1.0: 0.0},
 'TOOLIT_Clip_ExtendLast': {1.0: 0.0},
 'TOOLIT_Clip_Height': {1.0: 1920.0},
 'TOOLIT_Clip_ImportMode': {1.0: 0.0},
 'TOOLIT_Clip_InitialFrame': {1.0: 4294967295.0},
 'TOOLIT_Clip_Length': {1.0: 1.0},
 'TOOLIT_Clip_PullOffset': {1.0: 0.0},
 'TOOLIT_Clip_StartFrame': {1.0: 4294967295.0},
 'TOOLIT_Clip_TimeCode': {1.0: 0.0},
 'TOOLIT_Clip_TrimIn': {1.0: 0.0},
 'TOOLIT_Clip_TrimOut': {1.0: 0.0},
 'TOOLIT_Clip_Width': {1.0: 3840.0},
 'TOOLI_ID': 1.0,
 'TOOLI_ImageDepth': 5.0,
 'TOOLI_ImageField': -1.0,
 'TOOLI_ImageHeight': 1920.0,
 'TOOLI_ImageWidth': 3840.0,
 'TOOLI_Number_o_Inputs': 0.0,
 'TOOLNT_Clip_End': {1.0: 0.0},
 'TOOLNT_Clip_Start': {1.0: 0.0},
 'TOOLNT_EnabledRegion_End': {1.0: 1000000000.0},
 'TOOLNT_EnabledRegion_Start': {1.0: -1000000000.0},
 'TOOLNT_Region_End': {1.0: 999999999.9999},
 'TOOLNT_Region_Start': {1.0: 0.0},
 'TOOLN_ImageAspectX': 1.0,
 'TOOLN_ImageAspectY': 1.0,
 'TOOLN_LastFrameTime': 0.07738699999999987,
 'TOOLST_AltClip_FormatID': {},
 'TOOLST_AltClip_FormatName': {},
 'TOOLST_AltClip_Name': {1.0: ''},
 'TOOLST_Clip_FormatID': {1.0: 'JpegFormat'},
 'TOOLST_Clip_FormatName': {1.0: 'JpegFormat'},
 'TOOLST_Clip_KeyCode': {1.0: ''},
 'TOOLST_Clip_Name': {1.0: 'Reactor:/Deploy/Macros/KartaVR/Images/latlong_wide_ar.jpg'},
 'TOOLS_Name': 'Loader1',
 'TOOLS_RegID': 'Loader'}

'[args.prev Attributes]'
{'TOOLB_CacheToDisk': False,
 'TOOLB_CtrlWZoom': False,
 'TOOLB_HoldOutput': False,
 'TOOLB_Locked': False,
 'TOOLB_NameSet': False,
 'TOOLB_PassThrough': False,
 'TOOLB_Selected': True,
 'TOOLB_ShowControls': True,
 'TOOLB_Visible': True,
 'TOOLI_ID': 2.0,
 'TOOLI_Number_o_Inputs': 1.0,
 'TOOLNT_EnabledRegion_End': {1.0: 1000000000.0},
 'TOOLNT_EnabledRegion_Start': {1.0: -1000000000.0},
 'TOOLNT_Region_End': {1.0: 999999999.9999},
 'TOOLNT_Region_Start': {1.0: 0.0},
 'TOOLN_LastFrameTime': 0.0,
 'TOOLS_Name': 'Equirectangular2Fisheye',
 'TOOLS_RegID': 'GroupOperator'}

---------------------------------

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

Action Listener v2 Released

#191

Post by AndrewHazelden » Tue Oct 01, 2019 5:30 am

What's new in V2?

Version 2 of Action listener now tracks "Fusion" scope actions, in addition to the previous "comp" scope actions. This means creating a new comps, saving comps, and other tasks are captured more accurately now. Also, "comp:DoAction() is used for translating generic actions.

The difference in the quality of the recorded action results is like night and day. :)

If you have Action Listener installed via Reactor, now is the time to go back and update the "UI Manager Lua & Python Examples" atom package in the "Scripts/Comp" category.