No internet connection
  1. Home
  2. Support

Sequoia Popup Menu Challenges

By Tristan Hoogland @Tristan
    2024-11-19 21:26:23.820Z

    Hi ya'll!

    I just purchased a new M4 Macbook Pro preinstalled with sequoia and off the bat I'm running into issues with some of my scripts not playing nice with popup menu selections. I noticed there was one or two other forum posts pertaining to this, but curious what's the move here?

    Sometimes it works, sometimes it doesn't, but it is inconsistent - any help would be amazing. I'll keep digging in the meantime.

    Thanks!

    • 8 replies
    1. S
      SoundFlow Bot @soundflowbot
        2024-11-19 21:26:25.506Z

        Thanks for contacting SoundFlow support.

        Please note, that the best way to get help with a script, macro or other content installed from the Store or content that you've made yourself, is to select the script/macro, then click the red Need help button, and then click "Get help with this script or macro".
        By using this method, we will get access to more information and so should be able to help you quicker.
        You can read more about how this works here: bit.ly/sfscripthelp

        If you're seeing an error that isn't related to scripts or macros, and you think this is a bug in SoundFlow, please file a Help/Issue bug report.
        You can see how to do this by going to bit.ly/sfhelpissue

        1. In reply toTristan:
          Kitch Membery @Kitch2024-11-19 21:50:03.340Z

          Hi @Tristan,

          Due to changes that Apple made in Sonoma OS, popup menu calls are no longer synchronous.

          This will only really be a problem when directly sequencing... (menu -> popup menu) or (popup menu -> popup menu) ...type actions with no other wait in between.

          Therefore you'll now need to add implementation to ensure menus close before moving on.

          It's important to note that when working with asynchronous tasks the fix should never be to insert an arbitrary wait (sf.wait()) time, it's better to wait for a specific condition to be true rather than use arbitrary delays which might be unreliable or inefficient.

          So for these situations, you'd need to implement a waitFor() method with a callback to ensure that each popup menu closes before moving on.

          This approach will make your script robust and more precise, avoiding unnecessary waits or premature actions.

          Can you provide me with a simple example of a sequence of menus that is causing you a problem? That way I'll be able to provide you a solution you can use to update your scripts.

          Thanks in advance.

          1. TTristan Hoogland @Tristan
              2024-11-20 17:40:00.506Z

              Thanks @Kitch !

              Got it. I'm going deeper into some of my scripts today to see where I need to implement the waitFor() method.

              Here's an example snippet from one function that's failing currently.

                  //Set "Mix Source" - Popup Menu
                  if (bounceDlg.popupButtons.allItems[1].value.invalidate().value !== outputPath[outputPath.length - 1]) {
                      bounceDlg.popupButtons.allItems[1].popupMenuSelect({
                          menuPath: [outputPath[0], outputPath[outputPath.length - 1]],
                      });
                  }
              
              

              Thanks!

              1. Kitch Membery @Kitch2024-11-20 23:45:46.444Z

                @Tristan,

                Here's how I would do it.

                The popupMenuSelectAndWait function waits for the popup menu to close before moving on.

                /**
                 * @param {Object} args
                 * @param {AxElement} args.popupButton
                 * @param {String[]} args.menuPath
                 */
                function popupMenuSelectAndWait({ popupButton, menuPath }) {
                    // Wait for the Popup Button
                    popupButton.elementWaitFor();
                
                    // Click the Popu Putton to display and get the Popup Menu
                    const popupMenu = popupButton.popupMenuOpenFromElement({
                        anchor: "TopLeft", // Required to account for possible menu panel overlaps.
                        relativePosition: { x: 5, y: 5 }, // Required to make sure the menu is not being picked from the Popup Button's frame boundaries.
                    }).popupMenu;
                
                    // Select the Menu Path
                    popupMenu.menuClickPopupMenu({ menuPath }, () => {
                        sf.ui.frontmostApp.appActivateMainWindow(); // If the menu selection fails, activate the app's main window before throwing an error.
                        throw `Failed selecting menu path: ${JSON.stringify(menuPath)}`;
                    });
                
                    // Wait for the Popup Menu to no-longer have children in turn confirming that the menu has closed.
                    sf.waitFor({
                        callback: () => !popupMenu.invalidate().children.first.exists,
                        timeout: 2000,
                    });
                }
                
                
                const outputPath = ["physical output", "Mac Studio Speakers 1-2 (Stereo)"];
                
                sf.ui.proTools.appActivateMainWindow();
                
                const bounceDlg = sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first;
                
                
                //Set "Mix Source" - Popup Menu
                if (bounceDlg.popupButtons.allItems[1].value.invalidate().value !== outputPath[outputPath.length - 1]) {
                
                    popupMenuSelectAndWait({
                        popupButton: bounceDlg.popupButtons.allItems[1],
                        menuPath: outputPath
                    });
                }
                
                1. TTristan Hoogland @Tristan
                    2024-11-21 01:06:20.613Z

                    Thanks so much mate! And for today on the zoom too. Gonna start implementing this now, will fire back with results in the next few days!

                    1. In reply toKitch:
                      TTristan Hoogland @Tristan
                        2024-11-21 20:50:04.541Z

                        Hey @Kitch

                        Things are working great so far for most of the menus I'm tackling. Do you have any advice on a script moving too quickly through save as dialogs/sheets appearing? So far unless I put this 1000ms wait between the sheet appearing and the rest of the script it speeds right through:

                            let dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').first
                        
                            //TEMP WAIT
                            sf.wait({ intervalMs: 1000 });
                        
                            //Enter the new name
                            dlg.textFields.first.value.value = newName;
                        
                            //Click Save
                            dlg.buttons.whoseTitle.is('Save').first.elementClick();
                        

                        Without the small wait, it speeds right through this part and doesn't even get to the textfields/newName and Click Save part.

                        I've tried using callbacks on the save dialog, but it ain't working. Thanks in advance!

                        1. Kitch Membery @Kitch2024-11-22 00:20:52.743Z

                          Not exactly sure where it's failing, but this should deal with all scenarios that I can see.

                          let newName = "Test Session Name"
                          
                          // Activate Pro Tools
                          sf.ui.proTools.appActivate();
                          
                          // Open the "Save" window
                          sf.ui.proTools.menuClick({ menuPath: ["File", "Save Session As..."] });
                          
                          const saveSessionDialog = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').first;
                          
                          // Wait for "Save" window
                          saveSessionDialog.elementWaitFor();
                          
                          log(`The "Save" window appeared.`); // For demonstration purposes only.
                          
                          const saveAsTextField = saveSessionDialog.textFields.first;
                          
                          // Set "Save as" text field to newName
                          saveAsTextField.value.value = newName;
                          
                          sf.waitFor({
                              callback: () => saveAsTextField.value.invalidate().value === newName,
                              timeout: 2000,
                          }, `Could not set the "Save as" text field to ${newName}`);
                          
                          log(`"Save as" text field value sucessfully set to ${newName}`); // For demonstration purposes only.
                          
                          //Click Save
                          saveSessionDialog.buttons.whoseTitle.is('Save').first.elementClick();
                          
                          // Wait for the "Save" dialog to disappear
                          saveSessionDialog.elementWaitFor({ waitForNoElement: true });
                          
                          log(`The "Save" window closed.`); // For demonstration purposes only.
                          
                          1. TTristan Hoogland @Tristan
                              2024-11-22 22:51:32.291Z

                              Ugh, @Kitch obvious now - it was simply this line that was omitted from my script:

                              saveSessionDialog.elementWaitFor();
                              

                              Thanks!