Building GUIs With Fusion's UI Manager

User avatar
SirEdric
Fusionator
Posts: 2405
Joined: 10 years ago
Real name: Eric Westphal
Been thanked: 6 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#91

Unread post by SirEdric »

Heya.
Maybe I've overlooked something, but how would I get the index of a ui:tree element when clicked on?
Meaning:
When I select an Element I get stuff like:

Code: Select all

table: 0x03f7ce58
	when = 107530.281
	sender = UITree (0x000000003981C680) [App: 'Fusion' on 127.0.0.1, UUID: 8dc2b089-731c-4a94-80a6-5517e4e883d3]
	column = 0
	what = ItemClicked
	item = UITreeItem (0x0000000060CDE3E0) [App: 'Fusion' on 127.0.0.1, UUID: 8dc2b089-731c-4a94-80a6-5517e4e883d3]
	window = MyWin
	who = JobList
So I actually get the index of the *column* I clicked on.
But how would I get the index of the *row*?

Cheers.

Eric.

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Reading ui:Tree Rows and Cells

#92

Unread post by AndrewHazelden »

SirEdric wrote: 7 years ago So I actually get the index of the *column* I clicked on.
But how would I get the index of the *row*?
Hi SirEdric.

Open Reactor and download the "UI Manager Lua Examples" atom package.

In the Scripts:/Comp/UI Manager/ folder open up the files:
  • Tree.lua (shows direct cell editing and setting a value on the click)
  • List Input Control Names.lua (shows how to read the row text)
  • Media Tree.lua (shows how to read the row text)

The code chunk below is from "Media Tree.lua". It shows how to read a single click or double click of a row in the ui:Tree. This is based upon using the column index value you specify to indicate the data cell you want to read using "ev.item.Text[]".

In the Media Tree example the "2" in the command "ev.item.Text[2]" represents the Filepath column heading in the ui:Tree. You would write in the column index value you need to access there in-place of the 2.

Code: Select all

-- Copy the filepath to the clipboard when a Tree view row is clicked on
function win.On.Tree.ItemClicked(ev)
  -- Column 2 = Filepath
  sourceMediaFile = ev.item.Text[2]
  -- Copy the filepath to the clipboard
  CopyToClipboard(sourceMediaFile)
  
  -- print('[Item Selected] ' .. sourceMediaFile)
  -- print('\n')
end

-- Open up the folder where the media is located when a Tree view row is clicked on
function win.On.Tree.ItemDoubleClicked(ev)
  -- Column 2 = Filepath
  sourceMediaFile = ev.item.Text[2]
  
  -- Open up the folder where the media is located
  mediaFolder = Dirname(sourceMediaFile)
  if eyeon.fileexists(mediaFolder) then
     OpenDirectory(mediaFolder)
  end
  
  -- print('[Item Selected] ' .. sourceMediaFile)
  -- print('\n')
end

User avatar
SirEdric
Fusionator
Posts: 2405
Joined: 10 years ago
Real name: Eric Westphal
Been thanked: 6 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#93

Unread post by SirEdric »

Thanks mate!
But I still can't find a way to get the *index* of the row..
Reading the contents of the individiual cells is pretty straight forward, thanks to your excellent examples.
But all I need is ..well.. the number of the row that's been clicked on.
Like myRow = ev.item.row or myRow = ev.item.index....

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#94

Unread post by AndrewHazelden »

SirEdric wrote: 7 years ago Thanks mate!
But I still can't find a way to get the *index* of the row..
Reading the contents of the individiual cells is pretty straight forward, thanks to your excellent examples.
But all I need is ..well.. the number of the row that's been clicked on.
Like myRow = ev.item.row or myRow = ev.item.index....
I'm wrapping up a "Cave of Fusion" Easter Egg at this second so it will be a little while before I can dig deeper into this using the "Fusion Script Help Browser", and "Action Listener" to look for details.

If you want a simple answer, add an initial "Number" Column to the ui:Table as the first column. Populate that Number column with an incrementing number valve (you could use an approach similar to what Tree.lua uses to fill the ui:Tree.)

Then you could probe the values in the "Number" column cell you are interested in getting a row index for and use that as your index value. It would give you the result you are after and be able to be implemented this second.

User avatar
SirEdric
Fusionator
Posts: 2405
Joined: 10 years ago
Real name: Eric Westphal
Been thanked: 6 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#95

Unread post by SirEdric »

Righto...nice hackaround...:-)

Cheers & all the best.

Eric.

User avatar
bfloch
Fusioneer
Posts: 121
Joined: 10 years ago

Re: Building GUIs With Fusion's UI Manager

#96

Unread post by bfloch »

I get it. This might also help me with my problem. Thanks, I should have RTFM properly :)

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#97

Unread post by AndrewHazelden »

bfloch wrote: 7 years ago I get it. This might also help me with my problem. Thanks, I should have RTFM properly :)
This thread is a really long guide, with lots of really precise fine points that have to be followed for success. It's no suprise that things have to be reviewed and tried out a few times to get all the details out of the posts. :)

There are other ways to center a new UI Manager based window on the monitor, like you could poke around by browsing inside the various Fusion window layouts Lua tables to compute the placement of your window, etc.

The approach I used was chosen simply because it was able to be implemented in an evening after 10pm on the day I wrote the script with simple code, and it was done fairly easily from a research perspective since I was just plain text browsing the raw Fusion preference file in my text editor to look for anything with a window related dimension to it I could read and hook into. :lol:

User avatar
BigRoyNL
Fusioneer
Posts: 97
Joined: 10 years ago

Re: Building GUIs With Fusion's UI Manager

#98

Unread post by BigRoyNL »

Thanks for this great topic and useful information. I had two questions regarding the notification callbacks.

1. Have you been able to connect a notification in Python? Or only through Lua?

2. Have you been able to do the following without it 'holding' the main loop?

Code: Select all

-- this would be in a "startup.scriptlib" file

-- do initialization here
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
    
ui:AddNotify("Comp_Close", comp)
function disp.On.Comp_Close(ev)
  -- do whatever here
  disp:ExitLoop()
end

disp:RunLoop()
Currently it locks the console until the ExitLoop() is called. Which kind of defeats the purpose in my scenario, because I want to initialize something at comp open or new (did this in .scriptlib file) and then on comp close I wanted to unitialize.

Is there a way to have this "notification" callback connected without locking the console whilst the comp is open?

Side note: I have this at the top of my scriptlib file to ensure it only runs whenever a composition is initialized (I don't know of any other way to do this):

Code: Select all

while composition == nil do

    -- no comp: fusion is being started
    while fusion == nil do
        -- wait until fusion is initialized so we can start executing code
    end
    
    -- Anything printed here will not show in any console
    -- because it is outside of any comps!
end

-- Return when script is run from "Scripts" menu in composition
if Execute == nil then
    return
end

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#99

Unread post by AndrewHazelden »

BigRoyNL wrote: 7 years ago 1. Have you been able to connect a notification in Python? Or only through Lua?
As far as I know the new UI Manager system does fully exist for both the Lua and Python languages in Fusion 9.

Unfortunately BMD's documentation team has not shared any details on how the Python side of things work in Fusion 9 yet and there are simply no examples or scraps of information to work from. That has meant that I have not been able to explore those Python based aspects in detail like I have for Lua.

If your goal is to use Lua + scriptlibs to shoehorn Python code into things you are probably making your life harder at the moment TBH and you might want to re-evaluate the best choice of technologies available and documented in Fusion to achieve your specific goals.
BigRoyNL wrote: 7 years ago Is there a way to have this "notification" callback connected without locking the console whilst the comp is open?
Yes. Use the Event {} handling feature of a Fusion .fu file to achieve this goal to having your code chunk executed when the comp is closed. I will make a new example that shows how this is done.

Alternatively, another way to interface with a composite opening event via Lua is that you could use your own Console Fuse that is run every time a new Fusion composite is opened. This code is executed the second the new Console tab is initialized.

If you open Reactor and install the new "Commodore64" atom that is in the "Fun" category you can see an example of a Console Fuse that runs and prints an output to the Console tab every time Fusion starts up or a new composite is opened.

The fuse function you want to put your code inside of is called "function Attach(view)"

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

FusionCompEvents.fu

#100

Unread post by AndrewHazelden »

The "FusionCompEvents.fu" config file saves out a log file that tracks every single Fusion composite new/open/close/save event. This is done with a new .fu file based Event{} entry that intercepts the native action by appending our own custom Lua code. The Event.log file is written to your Fusion user prefs folder using the PathMap location of "UserData:/Event.log".

The key part of this event example is the line:

rets = self:Default(ctx, args)

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.

Choosing the Right Event Targets Setting

For events that happen before a composition object exists in memory the Event "Targets" setting needs to be "Fusion":

Code: Select all

Event {
	Action = "Comp_New",
	Targets = {
		Fusion = {
			Execute = ""
		},
	},
},
For events that happen when an individual composition is open and you want to monitor things that are occurring *inside* that specific comp, the Event "Targets" setting needs to be "Composition":

Code: Select all

Event {
	Action = "Comp_Close",
	Targets = {
		Composition = {
			Execute = ""
		},
	},
},
Download
FusionCompEvents.fu
Example Event.log Output

Code: Select all

[2018-01-31|04:06:19 PM]	[Save Comp] "/Library/Application Support/Blackmagic Design/Fusion/Reactor/Deploy/Comps/BarrelShape3D.comp"
[2018-01-31|04:06:20 PM]	[Close Comp] "/Library/Application Support/Blackmagic Design/Fusion/Reactor/Deploy/Comps/BarrelShape3D.comp"
[2018-01-31|04:06:36 PM]	[Save Comp] "/Library/Application Support/Blackmagic Design/Fusion/Reactor/Deploy/Comps/hos_Tiler.comp"
[2018-01-31|04:06:51 PM]	[Close Comp] "/Library/Application Support/Blackmagic Design/Fusion/Reactor/Deploy/Comps/hos_Tiler.comp"
Installation

Step 1. Copy the FusionCompEvents file to the Fusion user prefs "Config:/FusionCompEvents.fu" PathMap folder.

Step 2. Restart Fusion for the example to be activated.

Step 3. When you open and close Fusion composites a log entry is made by tracking "Comp_New", "Comp_Open", "Comp_Recent_Open", "Comp_Close" and "Comp_Save".

Opening the Log File

The new Event.log file is saved to the "UserData:/Event.log" PathMap Location.

Windows Event.log Location:

Code: Select all

%appdata%\Blackmagic Design\Fusion\Event.log
Linux Event.log Location:

Code: Select all

$HOME/.fusion/BlackmagicDesign/Fusion/Event.log
Mac Event.log Location:

Code: Select all

$HOME/Library/Application Support/Blackmagic Design/Fusion/Event.log
Note: $HOME represents your current user account's home folder.
You do not have the required permissions to view the files attached to this post.

User avatar
BigRoyNL
Fusioneer
Posts: 97
Joined: 10 years ago

Re: Building GUIs With Fusion's UI Manager

#101

Unread post by BigRoyNL »

Thanks Andrew, that would actually be perfect!

I tried this:

Code: Select all

{
	Event {
		Action = "Comp_Close",
		Targets = {
			Composition = {
				Execute = [[
rets = self:Default(ctx, args)
print("[Comp_Close]")
]]
			},
		},
	},
	Event {
		Action = "Comp_Opened",
		Targets = {
			Composition = {
				Execute = [[
rets = self:Default(ctx, args)
print("[Comp_Opened]")
]]
			},
		},
	},
	Event {
		Action = "Comp_Open",
		Targets = {
			Composition = {
				Execute = [[
rets = self:Default(ctx, args)
print("[Comp_Open]")
]]
			},
		},
	},
	Event {
		Action = "Comp_New",
		Targets = {
			Composition = {
				Execute = [[
rets = self:Default(ctx, args)
print("[Comp_New]")
]]
			},
		},
	},
	Event {
		Action = "Comp_Save",
		Targets = {
			Composition = {
				Execute = [[
rets = self:Default(ctx, args)
print("[Comp_Save]")
]]
			},
		},
	}

}
But somehow didn't get it to work for any Event aside from "Comp_Save".
It's the same with your example, somehow I didn't get it to write the Comp close to the log file.

Update: Ok, so I'm getting the saved and closed signals now.

There only seems to be a bug with the comp close signal when clicking on the "X" at the top of the comp to close it, the signal is not emitted. Only when I press CTRL+W or File>Close does the signal get emitted. I was initially closing with the "X" on the top of the Composition, it closed, but didn't log any event so I wasn't seeing anything. It's sad to see it's this unstable (tested on Win 7 + Fusion 9.0.2).

Also, I'm not getting any of the other signals to work like: "Comp_Open" or "Comp_Opened" or "Comp_New" anything along those lines. Anyone else?

I'm specifically looking to do something on Comp open (or new) - just whenever a composition window initializes for the first time and on Comp close - when the composition window closes.
Last edited by BigRoyNL 7 years ago, edited 1 time in total.

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Re: Building GUIs With Fusion's UI Manager

#102

Unread post by AndrewHazelden »

BigRoyNL wrote: 7 years ago Also, I'm not getting any of the other signals to work like: "Comp_Open" or "Comp_Opened" or anything along those lines. Anyone else?
There are still several ways that Fusion can do a task and an Action is only logged and tracked if it was used for carrying out the task. Otherwise if an internal function (that isn't an Action) was used you see nothing.

Edit: "Comp_Recent_Open" also doesn't seem to emit an event unless your Event section is targeting "Fusion" not "Composition".

Also, from a design perspective your code would have issues from the way the logic flows:

Code: Select all

rets = self:Default(ctx, args)
print("[Comp_Close]")
Having print written after self:Default() means ONLY AFTER the composite is fully closed would your print line be run... But the print command would be locked to outputting content into the scope of the Fusion Console tab that was active when the event was run so you wouldn't see it.

So, if you want your code to run BEFORE the close action is run by Fusion, put that line of Lua script above the self:Default() function in the event.

Without testing it right now, you would likely have to use "compList = fusion:GetCompList()" or "cmp = fusion.CurrentComp" to find out what the new compositing pointer is after your current document was closed. Then you would use the comp specific print command "obj:Comp():Print("\n")" like this to target the new foreground comp's Console tab:

Code: Select all

cmp = fusion.CurrentComp
cmp:Print("[Comp_Close]\n")

User avatar
BigRoyNL
Fusioneer
Posts: 97
Joined: 10 years ago

Re: Building GUIs With Fusion's UI Manager

#103

Unread post by BigRoyNL »

Having print written after self:Default() means ONLY AFTER the composite is fully closed would your print line be run... But the print command would be locked to outputting content into the scope of the Fusion Console tab that was active when the event was run so you wouldn't see it.

So, if you want your code to run BEFORE the close action is run by Fusion, put that line of Lua script above the self:Default() function in the event.
Yes, this should be totally correct. ;) I just quickly tried many of the events and maybe dropped a bit of a quick draft of code online - I definitely tested both. For sake of testing I could've maybe better used the logging one and always try to log before and after and see what still ends up being called. :) But thanks for pointing out here - it could definitely end up being useful to others, if the signals actually work. ;)

User avatar
AndrewHazelden
Fusius Of Borg
Posts: 2605
Joined: 10 years ago
Location: West Dover, Nova Scotia, Canada
Has thanked: 4 times
Been thanked: 18 times
Contact:

Monitoring "Comp_New", "Comp_Open", "Comp_Recent_Open" Events

#104

Unread post by AndrewHazelden »

BigRoyNL wrote: 7 years agoBut thanks for pointing out here - it could definitely end up being useful to others, if the signals actually work. ;)
Okay, it's now a few hours later and I've got the "Comp_New", "Comp_Open", "Comp_Recent_Open" events working and added to the previous .fu Events demo. As part of that change I renamed the example from "CloseSaveEvents.fu" to "FusionCompEvents.fu" and fully updated it to include the actions you were interested in.

Hope that help you on your project :)

The issue came down to changing the Event "Targets" section from monitoring the individual active foreground "Composition" over to monitoring the scope of "Fusion" since a new comp, or opening a comp wouldn't know what the comp object was called in advance of it existing. :oops: :P I learned something new today.

Cheers,
Andrew

User avatar
BigRoyNL
Fusioneer
Posts: 97
Joined: 10 years ago

Re: Building GUIs With Fusion's UI Manager

#105

Unread post by BigRoyNL »

Hi Andrew,

Thanks - that works!

It's a bit problematic that I can't rely on the "exit" action to always get triggered when a comp closes, but only whenever someone uses the action. It's probably similar the other way around, if someone would open a comp through a script it will likely not trigger the Open action. This all makes it slightly unreliable.

But it's good to learn this specific "target" thing about the events. Thanks again.

Cheers,
Roy