Q:

wxLua - How do I implement a Cancel button?

I have a wxLua Gui app that has a "Run" button. Depending on selected options, Run can take a long time, so I would like to implement a "Cancel" button/feature. But it looks like everything in wxLua is working on one Gui thread, and once you hit Run, pressing Cancel does nothing, the Run always goes to completion.
Cancel basically sets a variable to true, and the running process regularly checks that variable. But the Cancel button press event never happens while Running.
I have never used co-routines; if the Run process regularly yields to a "Cancel check" process, will the Cancel event happen then?
Or is there another way?

A:

(the following assumes that by "Run" you mean a long running operation in the same process and not running an external process using wxExecute or wxProcess.)
"Cancel" event is not triggered because by executing your Run logic you have not given a chance to the UI to handle the click event.
To avoid blocking the UI you need to do something like this. When you click Run button create a co-routine around the function you want to run:
coro = coroutine.create(myLongRunningFunction)

Your Run event is completed at this point. Then in EVT_IDLE event you will be resuming this coroutine as long as it's not complete. It will look something like this:
if coro then -- only if there is a coroutine to work on
  local ok, res = coroutine.resume(coro, additional, parameters)
  -- your function either yielded or returned
  -- you may check ok to see if there was an error
  -- res can tell you how far you are in the process
  -- coro can return multiple values (just give them as parameters to yield)
  if coroutine.status(coro) == 'dead' then -- finished or stopped with error
    coro = nil
    -- do whatever you need to do knowing the process is completed
  end
end

You will probably need to request more IDLE event for as long as your process is not finished as some operating systems will not trigger IDLE events unless there is some other event triggered. Assuming your handler has event parameter, you can do event:RequestMore(true) to ask for more IDLE events (RequestMore).
Your long-running process will need to call coroutine.yield() at the right time (not too short as you will be wasting time to switch back and forth and not too long for users to notice delays in the UI); you probably need to experiment with this, but something timer-based with 100ms or so between calls may work.
You can check for Cancel values either in your IDLE event handler or in the long-running function as you do now. The logic I described will give your application UI a chance to process Cancel event as you expect.

