3434
3535#include " windows/AboutWindow.h"
3636#include " AppSettings.h"
37+ #include " settings/SettingsBox.h"
38+
3739
3840using namespace juce ;
3941
@@ -110,18 +112,24 @@ class MainComponent : public Component,
110112 saveAs = 0x2003 ,
111113 undo = 0x2004 ,
112114 redo = 0x2005 ,
113- login = 0x2006
114- // settings = 0x2007,
115+ login = 0x2006 ,
116+ settings = 0x2007
115117 };
116118
117- StringArray getMenuBarNames () override { return { " File" }; }
119+ StringArray getMenuBarNames () override
120+ {
121+ // DBG("getMenuBarNames() called");
122+ return { " File" };
123+ }
118124
119125 // In mac, we want the "about" command to be in the application menu ("HARP" tab)
120126 // For now, this is not used, as the extra commands appear grayed out
121127 std::unique_ptr<PopupMenu> getMacExtraMenu ()
122128 {
123129 auto menu = std::make_unique<PopupMenu>();
124130 menu->addCommandItem (&commandManager, CommandIDs::about);
131+ menu->addCommandItem (&commandManager, CommandIDs::settings);
132+ menu->addCommandItem (&commandManager, CommandIDs::login);
125133 return menu;
126134 }
127135
@@ -137,10 +145,14 @@ class MainComponent : public Component,
137145 menu.addCommandItem (&commandManager, CommandIDs::undo);
138146 menu.addCommandItem (&commandManager, CommandIDs::redo);
139147 menu.addSeparator ();
140- // menu.addCommandItem (&commandManager, CommandIDs::settings);
141- // menu.addSeparator();
142- menu.addCommandItem (&commandManager, CommandIDs::login);
143- menu.addCommandItem (&commandManager, CommandIDs::about);
148+ // menu.addCommandItem (&commandManager, CommandIDs::settings);
149+ menu.addSeparator ();
150+ // menu.addCommandItem(&commandManager, CommandIDs::login);
151+ // menu.addCommandItem(&commandManager, CommandIDs::about);
152+ }
153+ else
154+ {
155+ DBG (" Unknown menu name: " << menuName);
144156 }
145157 return menu;
146158 }
@@ -158,7 +170,7 @@ class MainComponent : public Component,
158170 const CommandID ids[] = {
159171 CommandIDs::open, CommandIDs::save, CommandIDs::saveAs,
160172 CommandIDs::undo, CommandIDs::redo, CommandIDs::login,
161- CommandIDs::about
173+ CommandIDs::about, CommandIDs::settings
162174 };
163175 commands.addArray (ids, numElementsInArray (ids));
164176 }
@@ -199,12 +211,16 @@ class MainComponent : public Component,
199211 case CommandIDs::about:
200212 result.setInfo (" About HARP" , " Shows information about the application" , " About" , 0 );
201213 break ;
214+ case CommandIDs::settings:
215+ result.setInfo (" Preferences..." , " Open the settings window" , " Settings" , 0 );
216+ break ;
202217 }
203218 }
204219
205220 // Callback for the save and saveAs commands
206221 bool perform (const InvocationInfo& info) override
207222 {
223+ DBG (" perform() called" );
208224 switch (info.commandID )
209225 {
210226 case CommandIDs::open:
@@ -235,6 +251,10 @@ class MainComponent : public Component,
235251 DBG (" About command invoked" );
236252 showAboutDialog ();
237253 break ;
254+ case CommandIDs::settings:
255+ DBG (" Settings command invoked" );
256+ showSettingsDialog ();
257+ break ;
238258 default :
239259 return false ;
240260 }
@@ -733,6 +753,21 @@ class MainComponent : public Component,
733753 MessageManager::callAsync ([this , loadingError]
734754 { loadModelButton.setEnabled (false ); });
735755 }
756+ if (loadingError.userMessage .containsIgnoreCase (" sleeping" ))
757+ {
758+ MessageManager::callAsync ([this ] {
759+ addCustomPathToDropdown (customPath, true ); // mark as sleeping
760+ });
761+ }
762+ // NEW: reopen custom path dialog if sleeping or 404
763+ if (loadingError.type == ErrorType::InvalidURL ||
764+ loadingError.devMessage .contains (" 404" ) ||
765+ loadingError.userMessage .containsIgnoreCase (" sleeping" ))
766+ {
767+ MessageManager::callAsync ([this ] {
768+ openCustomPathDialog (customPath);
769+ });
770+ }
736771 };
737772
738773 AlertWindow::showAsync (msgOpts, alertCallback);
@@ -756,6 +791,31 @@ class MainComponent : public Component,
756791 });
757792 }
758793
794+ void openCustomPathDialog (const std::string& prefillPath = " " )
795+ {
796+ std::function<void (const juce::String&)> loadCallback =
797+ [this ](const juce::String& customPath2)
798+ {
799+ this ->customPath = customPath2.toStdString ();
800+ loadModelButton.triggerClick (); // Trigger load
801+ };
802+
803+ std::function<void ()> cancelCallback = [this ]()
804+ {
805+ if (lastLoadedModelItemIndex != -1 )
806+ modelPathComboBox.setSelectedId (lastLoadedModelItemIndex + 1 );
807+ else if (lastSelectedItemIndex != -1 )
808+ modelPathComboBox.setSelectedId (lastSelectedItemIndex + 1 );
809+ else
810+ resetModelPathComboBox ();
811+ };
812+
813+ CustomPathDialog* dialog = new CustomPathDialog (loadCallback, cancelCallback);
814+ if (!prefillPath.empty ())
815+ dialog->setTextFieldValue (prefillPath);
816+ }
817+
818+
759819 void resetModelPathComboBox ()
760820 {
761821 // cb: why do we resetUI inside a function named resetModelPathComboBox ?
@@ -784,6 +844,36 @@ class MainComponent : public Component,
784844 lastSelectedItemIndex = -1 ;
785845 }
786846
847+ // Adds a path to the model dropdown if it's not already present
848+ void addCustomPathToDropdown (const std::string& path, bool wasSleeping = false )
849+ {
850+ juce::String displayStr (path);
851+ if (wasSleeping)
852+ displayStr += " (sleeping)" ;
853+
854+ bool alreadyExists = false ;
855+ for (int i = 0 ; i < modelPathComboBox.getNumItems (); ++i)
856+ {
857+ if (modelPathComboBox.getItemText (i).startsWithIgnoreCase (path))
858+ {
859+ alreadyExists = true ;
860+ break ;
861+ }
862+ }
863+
864+ if (!alreadyExists)
865+ {
866+ int newID = modelPathComboBox.getNumItems () + 1 ;
867+ modelPathComboBox.addItem (displayStr, newID);
868+ }
869+
870+ modelPathComboBox.setText (displayStr, juce::dontSendNotification);
871+ }
872+
873+
874+
875+
876+
787877 void focusCallback ()
788878 {
789879 // if (mediaDisplay->isFileLoaded())
@@ -825,6 +915,20 @@ class MainComponent : public Component,
825915 // }
826916 }
827917
918+ void showSettingsDialog ()
919+ {
920+ DBG (" Settings command invoked" );
921+
922+ juce::DialogWindow::LaunchOptions options;
923+ options.dialogTitle = " Settings" ;
924+ options.content .setOwned (new SettingsBox ());
925+ options.useNativeTitleBar = true ;
926+ options.resizable = true ;
927+ options.escapeKeyTriggersCloseButton = true ;
928+ options.dialogBackgroundColour = juce::Colours::lightgrey;
929+ options.launchAsync ();
930+ }
931+
828932 void initMenuBar ()
829933 {
830934 // init the menu bar
@@ -833,13 +937,17 @@ class MainComponent : public Component,
833937 setApplicationCommandManagerToWatch (&commandManager);
834938 // Register commands
835939 commandManager.registerAllCommandsForTarget (this );
940+ commandManager.setFirstCommandTarget (this );
941+
836942 // commandManager.setFirstCommandTarget(this);
837943 addKeyListener (commandManager.getKeyMappings ());
838944
839945#if JUCE_MAC
840946 // Not used for now
841- // auto extraMenu = getMacExtraMenu();
842- MenuBarModel::setMacMainMenu (this );
947+ // auto extraMenu = getMacExtraMenu();
948+ // MenuBarModel::setMacMainMenu(this);
949+ macExtraMenu = getMacExtraMenu ();
950+ MenuBarModel::setMacMainMenu (this , macExtraMenu.get ());
843951#endif
844952
845953 menuBar->setVisible (true );
@@ -1116,6 +1224,7 @@ class MainComponent : public Component,
11161224 // set to full screen
11171225 // setFullScreen(true);
11181226 resized ();
1227+
11191228 }
11201229
11211230 ~MainComponent () override
@@ -1478,8 +1587,7 @@ class MainComponent : public Component,
14781587 menuBar->setBounds (
14791588 area.removeFromTop (LookAndFeel::getDefaultLookAndFeel ().getDefaultMenuBarHeight ()));
14801589#endif
1481-
1482- auto margin = 2 ; // Adjusted margin value for top and bottom spacing
1590+ auto margin = 2 ; // Adjusted margin value for top and bottom spacing
14831591
14841592 // Create a FlexBox container
14851593 juce::FlexBox flexBox;
@@ -1590,6 +1698,7 @@ class MainComponent : public Component,
15901698 std::unique_ptr<ModelStatusTimer> mModelStatusTimer { nullptr };
15911699
15921700 ComboBox modelPathComboBox;
1701+
15931702 // Two usefull variables to keep track of the selected item in the modelPathComboBox
15941703 // and the item index of the last loaded model
15951704 // These are used to restore the selected item in the modelPathComboBox
@@ -1680,6 +1789,7 @@ class MainComponent : public Component,
16801789
16811790 std::shared_ptr<fontawesome::IconHelper> fontawesomeHelper;
16821791 std::shared_ptr<fontaudio::IconHelper> fontaudioHelper;
1792+ std::unique_ptr<PopupMenu> macExtraMenu;
16831793
16841794 void play ()
16851795 {
0 commit comments