- Posts: 267
- Joined: Tue Oct 14, 2014 11:53 pm
Hey folks, I'm building a Workflow Integration for Resolve and I'm really stumped in trying to figure out a proper way to cancel a long process from a GUI button. I have a button that executes a function which iterates over a lot of items and takes a while. I would love to include a "Cancel" button next to the progress bar that allows the user to cancel the iterations. However, once the function is ran, the GUI locks up and button clicks are not registered until the function returns.
So far I've only come up with one way to do this, but it's kind of hacky and I feel like there must be a proper way. I've looked into Lua coroutines and the mysterious UITimer that isn't documented, but I couldn't figure out how to make those work.
Here's an example of what I've previously tried that does not work. The GUI is frozen until the "some_long_process" function returns.
And here's a hacky way that I've been able to do this. I'm writing the "some_long_process" function to disk as a lua script, then using RunScript to run that script which doesn't block the GUI, then using Fusion custom data to pass the cancel variable to it. This can't be the right way to do this though.
If anyone is generous enough to help me figure out the proper way to tackle this problem I would be really grateful!
Thanks!
So far I've only come up with one way to do this, but it's kind of hacky and I feel like there must be a proper way. I've looked into Lua coroutines and the mysterious UITimer that isn't documented, but I couldn't figure out how to make those work.
Here's an example of what I've previously tried that does not work. The GUI is frozen until the "some_long_process" function returns.
- Code: Select all
local temp_folder = Fusion():MapPath("Temp:")
local ui = Fusion().UIManager
local disp = bmd.UIDispatcher(ui)
local cancel
local some_long_process = function ()
print("beginning long process")
for i = 1, 10 do
if cancel then
return
end
print("executing: ", i)
bmd.wait(1)
end
print("ending long process")
return
end
local function my_window()
local width,height = 200, 50
local win = disp:AddWindow({
ID = "my_window",
WindowTitle = "My Window",
WindowFlags = {Window = true, WindowStaysOnTopHint = true,},
Geometry = {100, 100, width, height},
Spacing = 10,
Margin = 20,
ui:VGroup{
ID = 'root',
Weight = 0,
ui:HGroup{
Weight = 0,
ui:Button{
ID = "start",
Text = "Start",
},
ui:Button{
ID = "cancel",
Text = "Cancel",
},
},
},
})
win:RecalcLayout()
function win.On.start.Clicked(ev)
cancel = false
some_long_process()
end
function win.On.my_window.Close(ev)
disp:ExitLoop()
end
function win.On.cancel.Clicked(ev)
cancel = true
print("cancel clicked")
end
return win
end
local my_window = my_window()
my_window:Show()
disp:RunLoop()
my_window:Hide()
And here's a hacky way that I've been able to do this. I'm writing the "some_long_process" function to disk as a lua script, then using RunScript to run that script which doesn't block the GUI, then using Fusion custom data to pass the cancel variable to it. This can't be the right way to do this though.
- Code: Select all
local temp_folder = Fusion():MapPath("Temp:")
local ui = Fusion().UIManager
local disp = bmd.UIDispatcher(ui)
local some_long_process = function ()
print("beginning long process")
for i = 1, 10 do
cancel = Fusion():GetData('cancel')
if cancel then
print("long process cancelled")
return
end
print("executing: ", i)
bmd.wait(1)
end
print("ending long process")
return
end
local function my_window()
local width,height = 200, 50
local win = disp:AddWindow({
ID = "my_window",
WindowTitle = "My Window",
WindowFlags = {Window = true, WindowStaysOnTopHint = true,},
Geometry = {100, 100, width, height},
Spacing = 10,
Margin = 20,
ui:VGroup{
ID = 'root',
Weight = 0,
ui:HGroup{
Weight = 0,
ui:Button{
ID = "start",
Text = "Start",
},
ui:Button{
ID = "cancel",
Text = "Cancel",
},
},
},
})
win:RecalcLayout()
function win.On.start.Clicked(ev)
Fusion():SetData('cancel', nil)
local serialized = string.dump(some_long_process)
local path = temp_folder.."some_long_process.lua"
local out = io.open(path, "wb")
out:write(serialized)
out:close()
Fusion():RunScript(path)
end
function win.On.my_window.Close(ev)
Fusion():SetData('cancel', nil)
os.remove(temp_folder.."some_long_process.lua")
disp:ExitLoop()
end
function win.On.cancel.Clicked(ev)
Fusion():SetData('cancel', true)
os.remove(temp_folder.."some_long_process.lua")
end
return win
end
local my_window = my_window()
my_window:Show()
disp:RunLoop()
my_window:Hide()
If anyone is generous enough to help me figure out the proper way to tackle this problem I would be really grateful!
Thanks!