This one is slightly more complex. Come on.
console.abortEnabled = true;
This is a necessary step, but it is not sufficient. You must allow the core application to process interface events during your running routine, or the Pause/Abort button will never have a chance to work as such.
You have several ways to implement this behavior. One of them is through the "status monitoring" feature of images in PCL/PJSR. For example, consider the following snippet:
function AVeryHeavyAndLongTask( img )
{
// Initialize img's status monitor
img.statusEnabled = true;
img.initializeStatus( "Be prepared to wait, my friend", img.width*img.height*img.numberOfChannels );
for ( var c = 0; c < img.numberOfChannels; ++c )
for ( var y = 0; y < img.height; ++y )
{
// Do your heavy stuff here for a row of pixels
// Update the status monitor of the image
img.advanceStatus( img.width );
}
// In case of doubt, make sure we reach the total monitor count
img.completeStatus();
}
Each time your code calls Image.advanceStatus(), PixInsight Core's GUI has a chance to process all pending events, including all unprocessed mouse events for the Pause/Abort button, if any, all console and image updates, etc. The typical percent progress indicator will be incremented and shown on the console to reflect the current monitoring count, which is good because in this way you provide feedback to the user.
This also means that you should not call this function too often, or you'll get a significant performance degradation, as GUI updates and event processing are relatively expensive. You must achieve a reasonable "granularity" for your event processing by adjusting the interval (in terms of relative computational work carried out) between two successive calls to advanceStatus(). Too fine-grained processing will lead to performance degradation; too little event processing will lead to an unresponsive interface most of the time.
The second way you have to ensure proper event processing is much simpler, although less eye-candy —the eye candy and the feedback given to the user, if any, are your entire responsibility. Just call the processEvents() global function somewhere inside your main loop:
function AVeryHeavyAndLongTask( img )
{
for ( var c = 0; c < img.numberOfChannels; ++c )
for ( var y = 0; y < img.height; ++y )
{
// Do your heavy stuff here for a row of pixels
// Process pending GUI events
processEvents();
}
}
The same remarks made for Image's status monitor are valid here. processEvents() performs the same tasks except no feedback is provided on the console, so the user "doesn't know" what's happening unless you do something explicitly. Note also that the Console.abortEnabled property must also be set to true before calling processEvents(), or the Pause/Abort button will be disabled anyway.
In both cases, if the user clicks Pause/Abort and says Yes to the question "Do you want to abort..." your code will receive an exception. You can catch that exception to perform any necessary cleanup, but you should terminate script execution immediately if you do that. Of course, if you don't catch the exception (with a try {} catch {} construct) your script will be aborted as soon as it is thrown.