8 Replies Latest reply on Jan 16, 2015 11:23 AM by LeoTaro

    Progress Bar in SnippetRunner Sample

    DollarBillStern Level 1

      The progress bar in the SnippetRunner sample is bafflingly operational.  I can't figure out how it works.  Seemingly all it does is make a call to AIUserSuite->SetProgressText and then calls to AIUserSuite->UpdateProgress.  When I try to use this code I don't get any progress bar.  But honestly that makes sense to me.  I don't see how this sample even works.  Also, it only works when you select the ProgressBar snippet and choose run.  The other progress bars in the other snippets have never shown up for me.

       

      This is all part of a deeper issue that I'm trying to solve.  Maybe y'all can offer some suggestions.  I'm listening for the event thrown before a menu item.  I am sending a message out to an extendscript when the BEFORE menu item event is triggered.  But sending a message to extendscript is asynchronous of the SDK so the the menu item is carried out before the business in the extendscript gets a chance to play out. I'd like to stall illustrator (without having the user click anything like a warning box) in order to let the extendscript finish first. Hence the progress bar idea. Is there any other way?

       

       

      ASErr SnpProgressBar::BasicProgressBar()

      {

        ASErr result = kNoErr;

       

      // Set text of progress bar.

        this->SetProgressText(ai::UnicodeString("BasicProgressBar"));

       

      // Loop performing long running set of tasks.

        const ai::int32 max = 10000;

        for (ai::int32 taskNumber = 0; taskNumber < max; taskNumber++)

        {

             // Perform task

             for (ai::int32 j = 0; j < 100000; j++)

             {

                  this->MyTask(taskNumber, j);

             }

       

             // Update progress.

             this->UpdateProgress(taskNumber + 1, max);

       

             // Check for cancellation.

             if (this->IsCancelled()) {

                  result = kCanceledErr;

                  break;

             }

        }

       

      // Close progress bar.

        this->CloseProgress();

       

        return result;

      }

        • 1. Re: Progress Bar in SnippetRunner Sample
          A. Patterson Level 4

          Its been a long time since I tried to use the Illustrator progress bar -- we gave up years ago and rolled our own. I won't say that wasn't full of problems (Qt integration has its eccentricities as it is, a semi-modal dialog is 10x worse) but at least ours works So I can't help there.

           

          First, how do you execute a script from C++? I looked into that briefly a few months ago and came away with nothing. I'm curious how you managed it.

           

          Second, I'm not sure progress is a good way to block waiting for the script. It's an interesting problem though. I'm not very familiar with ExtendScript, so I can't remember what's available or not -- I don't suppose it supports ports or anything like that? It might be better to put the C++ into a loop with a timeout and have the script send a keep-alive every so often that resets the timeout. The same mechanism could send an All-Done message at the end.

           

          Actually, now if you can support CS6+, I believe scripts can send messages directly to the plugin through ScriptMessage() -- so that it is completely possible. It's a bit complex, but it'd probably be more reliable than using the progress -- though obviously it'd be nice if there was some kind of work indicator.

          • 2. Re: Progress Bar in SnippetRunner Sample
            DollarBillStern Level 1

            I am modeling after the UI samples provided in the CC2014 SDK.  They allow you to create and dispatch events that a JavaScript can listen for.  Then the javascript UI can call down to extendscript. Extendscript can call back to AI with ScriptMessage() as you said.

             

            I actually did try to implement the loop scenario you proposed, but unfortunately when my plugin is in a loop it won't hear messages from the extendscript until it times out.  If I return control to AI after I call the script by showing an alert message then my plugin is free and able to receive the message from extendscript. But I don't want the user to have to click cancel or OK, hence the idea for the progress bar.

             

            Basically It seems as though I need a way to have control wrestled away form illustrator while also having the SDK code "paused" or "idle" in a listening mode so that I can hear that extendscript ScriptMessage that says "I'm Done!"

            • 3. Re: Progress Bar in SnippetRunner Sample
              DollarBillStern Level 1

              I just realized that wasn't super specific about how to call extendscript.  Adobe provides a JavaScript file called CSInterface that defines a function called evalScript(script, callback) that allows messaged to be sent to extendscript and then the callback parameter allows you to get info back.

               

              Also, is there anyway that I can programmatically close an SDK warning dialog?  Then could just show a warning dialog that says "please wait while whatever is happening happens" and then shut it when extendscript returns control... I don't know. Grasping at straws.

              • 4. Re: Progress Bar in SnippetRunner Sample
                A. Patterson Level 4

                No, no way to do that that I know of, but it gave me a thought. You could pop your own semi-modal dialog -- that way you'd have control over when its closed. Being semi-modal would mean that it would lock down Illustrator so the user couldn't do anything else, but it wouldn't bock execution -- that's what our in-house progress dialog does (and I expect most progress dialogs necessarily do). It's not super hard to do with Qt (though it comes with a bag of odd issues you have to deal with) but I don't know how to do it exactly with Win32/OSX calls, but I'm sure it's doable on both platforms; presumably there'd be sample code out there.

                • 5. Re: Progress Bar in SnippetRunner Sample
                  LeoTaro Level 4

                  DollarBillStern wrote:

                   

                  The progress bar in the SnippetRunner sample is bafflingly operational.  I can't figure out how it works.  Seemingly all it does is make a call to AIUserSuite->SetProgressText and then calls to AIUserSuite->UpdateProgress.  When I try to use this code I don't get any progress bar.  But honestly that makes sense to me.  I don't see how this sample even works.  Also, it only works when you select the ProgressBar snippet and choose run.  The other progress bars in the other snippets have never shown up for me.

                   

                   

                   

                         // Check for cancellation.

                         if (this->IsCancelled()) {

                              result = kCanceledErr;

                              break;

                         }

                    }

                   

                  I think you will find that IsCancelled() calls AIUser::Cancel, which gives a chance for the user to cancel the progress bar. This allows pending events to be processed and also allows the progress bar to be shown. I think the reason the other progress bars don't show up is because the progress bar will only be shown if an operation has taken more than a certain time (seems to be about 3 or 4 seconds)

                  • 6. Re: Progress Bar in SnippetRunner Sample
                    DollarBillStern Level 1

                    That's an interesting theory.  But when I use the exact code from the progress bar class in my own plugin, it still doesn't work.  Within the progress bar sample I have noticed that if I step through the code, the progress bar usually pops up the second time through the main loop of BasicProgressBar.  It shows up when I step past UpdateProgress() but before I step past IsCancelled(). If I change the MAX value (the main loop limit) to be a lower number it will take a few more times stepping past UpdateProgress.  Sometime the progress bar won't show up if Max is dramatically lowered.  Sometimes it just flickers and goes away even though the loop hasn't finished.

                     

                    I also started questioning if this will even solve my problem as I'm wondering if the fact that the plug-in is in a progress bar loop will prevent it from hearing the callback from the script. It's all pretty annoying. I'm not sure that adding a QT layer to this is really desirable nor will it be possible time-wise considering I have never used QT. I think I am going to have to just monitor if the artboard is changed and just constantly be doing live updates. I hope that doesn't slow things down too much for the user.

                    • 7. Re: Progress Bar in SnippetRunner Sample
                      A. Patterson Level 4

                      Sorry, it's been so long that I took it as given that some of my knowledge was commonplace -- yes, the AI progress bar will not show until a set amount of time has passed. We had to replicate this behaviour in our Qt dialog. That turns out to be important, because as soon as the progress dialog is showing, you're taking a performance hit, not just from showing it, but the overhead of building, popping & shutting it down. It's actually quite noticeable (in Qt, and probably AI's as well).

                       

                      I don't recommend using Qt for just this, I was only saying I've spent a fair bit of time building my own in Qt so I know many of the pratfalls. I think it is a possible solution to try and roll your own simple one in the OS API though. Not a fun exercise, but it might solve your problem if you go that route.

                      • 8. Re: Progress Bar in SnippetRunner Sample
                        LeoTaro Level 4

                        DollarBillStern wrote:

                         

                        That's an interesting theory.  But when I use the exact code from the progress bar class in my own plugin, it still doesn't work. 

                        Are you calling the code as a result of a plugin message or from a callback? If it is from a callback are you setting the AppContext before calling the code?

                         

                        This is all part of a deeper issue that I'm trying to solve.  Maybe y'all can offer some suggestions.  I'm listening for the event thrown before a menu item.  I am sending a message out to an extendscript when the BEFORE menu item event is triggered.  But sending a message to extendscript is asynchronous of the SDK so the the menu item is carried out before the business in the extendscript gets a chance to play out. I'd like to stall illustrator (without having the user click anything like a warning box) in order to let the extendscript finish first. Hence the progress bar idea. Is there any other way?


                        What are you doing in the extendscript code? Can't you do the same thing within your plugin code?