Best practices for a Confirmation popup windows in plugins?


#1

Hi All!
I’ve searched the forum but the only thing I found is “don’t use runModalLoop in plugins”.
But may be people can share their best practices for splash screens/confirmation dialogs implementation?

For example, if you got a few file names in a collection, and want to ask user if he still needs these, and I have to do it file-by-file, what would you do?

With modal dialog it’s pretty straightforward - just cycle through the collection and bring a dialog like “do you need a file ABC? yes/no”, wait for a user response and go to next file.

With callbacks it looks like I have to make a function that cycles through the collection, opens the confirmation dialog for an item N and then passes all the info (file name, the file index (N) in a collection etc) to the confirmation dialog, and then finally leaves that function.

The dialog should pass all this info to the callback.

Then in the dialog callback (upon user response) I have to check if the collection is still alive (as it’s asynchronous now), was it changed maybe etc etc, then delete the file from collection and then pass the index back to the initial function that cycles through the collection so that it could proceed with next item…

Looks kinda complex.
Am I overlooking some simple and obvious solution?


#2

A lot of people keep it simple, and just add a 50% translucent component with their “popup” dialog controls contained within that covers up the main GUI. it’ll capture all of the mouse events blocking the users from interacting with the GUI.

just add it to your GUI editor as the top-most child as needed, and hide/delete when no longer needed.


#3

That is not the problem, really.
My question is about the program execution flow.

With runmodalloop the you can wait for user response in some particular point of your code, and if you need to ask 10 different confirmations in line - it is easy and simple.

With callbacks - the call to confirmation dialog is non-blocking (as far as I understand), thus the code structure have to be much more complex

So the questions is - can I make a blocking call to confirmation dialog (no matter if it would be a modal dialog or not) without going into various troubles associated with runmodalloop and plugin destruction during the active modal dialog?


#4

Any reason you don’t want to use this : https://docs.juce.com/master/classDialogWindow.html#a4e7934b53c5a76398cefb697d709a251

I think that’s pretty much your only option if you want to block.

edit : https://docs.juce.com/master/structDialogWindow_1_1LaunchOptions.html


#5

The use of blocking in plugins is frowned upon for very good reasons:

You are not only blocking your plugin’s code, you are not returning control to the host. So it is very easy to end up in situations, where your blocking conflicts with what the host shows the user. And that might even be only a problem in a specific DAW, that you never heard of, or that you can’t access to try to fix or workaround.

The next problem is, your plugin is not only running as one instance, but any number of instances of plugins. It is a nuisance for the user, if plugins open up dialog boxes, sometimes even multiple times. And that could happen, even if you have a static class, where you keep your confirmation result, because some hosts run in different processes.

I use the technology @matkatmusic described above quite successfully.
It is not too hard to keep a flag somewhere, if you showed the confirmation dialog already, and what the answer to that dialog was.

Another side note, it is good advice, not to run blocking code immediately, since some hosts create a plugin instance in the background, just to destroy it immediately. If that invisible plugin blocks the host, well… there is only the kill application from there…

Really, try to avoid it…


#7

Well, can you propose a reasonable solution for the problem I described in the first message of this thread?
How would you implement it?

It does not connected with modal dialog in any way. It just uses the modal dialog is an easy solution for waiting for a user response on a UI thread.
I don’t need the dialog to be modal, really…


#8

Sorry if I’m wrong, but as far as I understand, it can’t block plugin UI thread without using runModalLoop? If so, it’s a no-go for plugins


#9

Sure, I would do something like that (not tested, there will be errors):

In your Editor:

std::unique_ptr<FileDeleteDialog> fileDeleteDialog;

void deleteFiles (Array<File> files)
{
    for (auto file : files) file.deleteFile();
}
void closeFileDeleteDialog() 
{ 
    fileDeleteDialog.reset();
}
// ...

class FileDeleteDialog : public Component
{
    FileDeleteDialog (const Array<File> files, 
                      std::function<void(Array<File>)>& acceptFunction, 
                      std::function<void()> closeFunction)
    {
        // add a ListBox with your files and checkboxes

        addAndMakeVisible (closeButton);
        addAndMakeVisible (acceptButton);

        closeButton.onClick = closeFunction;
        acceptButton.onClick = [this, acceptFunction, closeFunction]()
        {
            acceptFunction (selectedFiles);
            closeFunction ();
        }
    }
private:
    Array<File> selectedFiles;
    TextButton closeButton { "Close" };
    TextButton acceptButton { "Delete" };
}

// and create with
fileDeleteDialog.reset (new FileDeleteDialog (
    filesToDelete,
    [this](Array<File> files) { deleteFiles (files); },
    [this]() { closeFileDeleteDialog(); });
addAndMakeVisible (fileDeleteDialog.get());
fileDeleteDialog.setBounds (getLocalBounds);

#10

Thanks!
So there is no solution for waiting on a UI thread.
I mean that listbox is obvious approach if you don’t need to make say 30 separate confirmation windows.
Thus was my question.


#11

Yes, I think it makes sense to collate that into one UI. And the asynchronous is the preferred approach, so the host can continue it’s job in the background.

And from a users perspective I think it is a good choice to not sequentially go through dialog after dialog…

Good luck, let me know, if you get problems with that approach…


#12

Unfortunately it does not answer my question, thus it does not fit my needs.
The files list processing with per-file confirmation was just a simplified example task.
And a per-file confirmation was the main part of the example…


#13

The goal seems not the example, but rather to block the host. IMHO it will result in a bad user experience, that’s why there are no answers.
Fair enough…

But good luck finding a solution anyway…


#14

if any piece of software made me click through 30 separate confirmations, it would get uninstalled pretty quickly


#15

Funny ))))
Have you ever coded any configuration wizards where every particular user decision (confirmation) affects numerous next steps (with it’s own questions/confirmations etc)?


#16

Well those are not separate then, are they?

You’re being extremely vague about what exactly you’re trying to achieve, yet poo-pooing any suggestions, so without being more specific people just have to guess at what you actually want to achieve.

If it is a wizard style dialogue, then why not a simple state machine?


#17

Because “older” way to do it was the popup dialogs blocking the UI thread till user response.
The state machine is obvious substitution, as I already stated in my very first message.
But it is normal to search for a most inexpensive way to modify existing and working software, isn’t it?

As for a generic example and “poo-pooing” as you called it ))) For obvious reasons I can’t just post the full task/product description here…
And the question was how to block UI thread and wait for user response.
No need for modal window etc.
The modal dialog was just a common way to do it, and I asked for a substitution without code redesign.

If it’s impossible, the good answer is “it’s impossible, you need to take different design decision.” I can surely re-code everything, just thought that may be there is a way to wait on UI thread without going modal.

Hopefully my question is clear now, and probably the answer is “no”.


#18

Yep, the answer is “it’s impossible, you need to take different design decision”.
I had missed the fact it was a plugin. As an exercise try building a noddy plugin that calls the blocking modal confirmation provided by JUCE and see how it affects the host. (It’s not good!)


#19

I really don’t understand why everyone is so fixated on a modal behavior.

In case of plugin it is elementary task to emulate dialog modality for this particular plugin window without affecting any other window including host (if needed).

Probably it’s because of the way I ask questions ))) sorry about that!


#20

IMHO (sorry to repeat) it is, because the message thread has to be shared with the host, so you are affecting an environment, that will behave very different and unpredictable to your program, if it doesn’t return control back to the host.

No need to be sorry, we really simply try to understand and to help… communication sometimes needs a bit back and forth… :slight_smile:


#21

The point was “if you block the UI thread, see what happens to the host”, unfortunately using the blocking modal as an example. :wink: It boils down to : you can’t block the UI thread, consequently you’re left with no option but to rethink your design accordingly I’m afraid.
I agree it’s a very common requirement, but I think it must be due to the design of the plugin hosting. Given what happens when you do block, I can only assume that they use a cooperative model.
edit: actually thinking about it, you can’t even do very long running operations from the UI thread for the same reason, you end up having to offload those onto a separate thread, or make the host completely unresponsive in the mean time :frowning: