Browse Source

Add MessageBoxOptions class for specifying a set of AlertWindow and NativeMessageBox options

- Add AlertWindow::show() and showAsync() methods that take a MessageBoxOptions argument
  - Add NativeMessageBox::show() and showAsync() methods that take a MessageBoxOptions argument
  - Update the DialogsDemo to demonstrate the new methods
  - Deprecate AlertWindow::showNativeDialogBox() in favour of the NativeMessageBox methods
  - Pass button strings specified in MesssageBoxOptions to native dialog boxes correctly
  - Use modern TaskDialog on Windows for the native dialog box where available
v6.1.6
ed 3 years ago
parent
commit
551d7b9c5b
54 changed files with 1338 additions and 576 deletions
  1. +5
    -1
      examples/Assets/DSPDemos_Common.h
  2. +7
    -4
      examples/Audio/AudioPlaybackDemo.h
  3. +5
    -5
      examples/Audio/AudioRecordingDemo.h
  4. +1
    -1
      examples/Audio/MPEDemo.h
  5. +1
    -1
      examples/GUI/AccessibilityDemo.h
  6. +3
    -3
      examples/GUI/CameraDemo.h
  7. +77
    -51
      examples/GUI/DialogsDemo.h
  8. +1
    -1
      examples/GUI/PropertiesDemo.h
  9. +6
    -6
      examples/GUI/VideoDemo.h
  10. +2
    -2
      examples/Utilities/InAppPurchasesDemo.h
  11. +5
    -5
      examples/Utilities/OSCDemo.h
  12. +72
    -44
      examples/Utilities/PushNotificationsDemo.h
  13. +1
    -1
      extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp
  14. +2
    -2
      extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp
  15. +2
    -2
      extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h
  16. +3
    -3
      extras/Projucer/Source/Application/jucer_Application.cpp
  17. +7
    -7
      extras/Projucer/Source/Application/jucer_AutoUpdater.cpp
  18. +3
    -3
      extras/Projucer/Source/Application/jucer_MainWindow.cpp
  19. +1
    -1
      extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp
  20. +1
    -1
      extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp
  21. +1
    -1
      extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp
  22. +1
    -1
      extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp
  23. +2
    -2
      extras/Projucer/Source/Project/Modules/jucer_Modules.cpp
  24. +2
    -2
      extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h
  25. +6
    -6
      extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h
  26. +1
    -1
      extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h
  27. +1
    -1
      extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp
  28. +1
    -1
      extras/Projucer/Source/Project/jucer_Project.cpp
  29. +1
    -1
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h
  30. +2
    -2
      extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp
  31. +4
    -4
      modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp
  32. +1
    -1
      modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp
  33. +0
    -21
      modules/juce_gui_basics/components/juce_ModalComponentManager.cpp
  34. +15
    -3
      modules/juce_gui_basics/components/juce_ModalComponentManager.h
  35. +3
    -3
      modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp
  36. +2
    -0
      modules/juce_gui_basics/juce_gui_basics.cpp
  37. +1
    -0
      modules/juce_gui_basics/juce_gui_basics.h
  38. +5
    -5
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  39. +1
    -1
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h
  40. +4
    -4
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp
  41. +1
    -1
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.h
  42. +66
    -39
      modules/juce_gui_basics/native/juce_android_Windowing.cpp
  43. +97
    -57
      modules/juce_gui_basics/native/juce_ios_Windowing.mm
  44. +89
    -7
      modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  45. +109
    -53
      modules/juce_gui_basics/native/juce_mac_Windowing.mm
  46. +279
    -59
      modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  47. +128
    -69
      modules/juce_gui_basics/windows/juce_AlertWindow.cpp
  48. +72
    -34
      modules/juce_gui_basics/windows/juce_AlertWindow.h
  49. +141
    -0
      modules/juce_gui_basics/windows/juce_MessageBoxOptions.h
  50. +87
    -43
      modules/juce_gui_basics/windows/juce_NativeMessageBox.h
  51. +1
    -1
      modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp
  52. +4
    -4
      modules/juce_gui_extra/documents/juce_FileBasedDocument.cpp
  53. +3
    -3
      modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.cpp
  54. +2
    -2
      modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.cpp

+ 5
- 1
examples/Assets/DSPDemos_Common.h View File

@@ -612,7 +612,11 @@ private:
auto u = fc.getURLResult(); auto u = fc.getURLResult();
if (! audioFileReader.loadURL (u)) if (! audioFileReader.loadURL (u))
NativeMessageBox::showOkCancelBox (AlertWindow::WarningIcon, "Error loading file", "Unable to load audio file", nullptr, nullptr);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Error loading file")
.withMessage ("Unable to load audio file"),
nullptr);
else else
thumbnailComp.setCurrentURL (u); thumbnailComp.setCurrentURL (u);
} }


+ 7
- 4
examples/Audio/AudioPlaybackDemo.h View File

@@ -529,10 +529,13 @@ private:
} }
else else
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::WarningIcon, "Enable Code Signing",
"You need to enable code-signing for your iOS project and enable \"iCloud Documents\" "
"permissions to be able to open audio files on your iDevice. See: "
"https://forum.juce.com/t/native-ios-android-file-choosers");
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Enable Code Signing")
.withMessage ("You need to enable code-signing for your iOS project and enable \"iCloud Documents\" "
"permissions to be able to open audio files on your iDevice. See: "
"https://forum.juce.com/t/native-ios-android-file-choosers"),
nullptr);
} }
} }
} }


+ 5
- 5
examples/Audio/AudioRecordingDemo.h View File

@@ -359,11 +359,11 @@ private:
fileToShare.deleteFile(); fileToShare.deleteFile();
if (! success && error.isNotEmpty()) if (! success && error.isNotEmpty())
{
NativeMessageBox::showMessageBoxAsync (AlertWindow::WarningIcon,
"Sharing Error",
error);
}
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Sharing Error")
.withMessage (error),
nullptr);
}); });
#endif #endif


+ 1
- 1
examples/Audio/MPEDemo.h View File

@@ -524,7 +524,7 @@ private:
void handleInvalidLegacyModeParameters() const void handleInvalidLegacyModeParameters() const
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Invalid legacy mode channel layout", "Invalid legacy mode channel layout",
"Cannot set legacy mode start/end channel:\n" "Cannot set legacy mode start/end channel:\n"
"The end channel must not be less than the start channel!", "The end channel must not be less than the start channel!",


+ 1
- 1
examples/GUI/AccessibilityDemo.h View File

@@ -193,7 +193,7 @@ private:
addAndMakeVisible (textButton); addAndMakeVisible (textButton);
shapeButton.setShape (getJUCELogoPath(), false, true, false); shapeButton.setShape (getJUCELogoPath(), false, true, false);
shapeButton.onClick = [] { AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Alert", "This is an AlertWindow"); };
shapeButton.onClick = [] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Alert", "This is an AlertWindow"); };
addAndMakeVisible (shapeButton); addAndMakeVisible (shapeButton);
} }


+ 3
- 3
examples/GUI/CameraDemo.h View File

@@ -252,7 +252,7 @@ private:
} }
else else
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Camera open failed",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Camera open failed",
"Camera open failed, reason: " + error); "Camera open failed, reason: " + error);
} }
@@ -365,7 +365,7 @@ private:
void errorOccurred (const String& error) void errorOccurred (const String& error)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Camera Device Error", "Camera Device Error",
"An error has occurred: " + error + " Camera will be closed."); "An error has occurred: " + error + " Camera will be closed.");
@@ -378,7 +378,7 @@ private:
void sharingFinished (bool success, bool isCapture) void sharingFinished (bool success, bool isCapture)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
isCapture ? "Image sharing result" : "Video sharing result", isCapture ? "Image sharing result" : "Video sharing result",
success ? "Success!" : "Failed!"); success ? "Success!" : "Failed!");


+ 77
- 51
examples/GUI/DialogsDemo.h View File

@@ -89,19 +89,14 @@ public:
// This method gets called on the message thread once our thread has finished.. // This method gets called on the message thread once our thread has finished..
void threadComplete (bool userPressedCancel) override void threadComplete (bool userPressedCancel) override
{ {
if (userPressedCancel)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Progress window",
"You pressed cancel!");
}
else
{
// thread finished normally..
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Progress window",
"Thread finished ok!");
}
const String messageString (userPressedCancel ? "You pressed cancel!" : "Thread finished ok!");
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Progress window")
.withMessage (messageString)
.withButton ("OK"),
nullptr);
// ..and clean up by deleting our thread object.. // ..and clean up by deleting our thread object..
delete this; delete this;
@@ -177,12 +172,13 @@ public:
[] (bool granted) [] (bool granted)
{ {
if (! granted) if (! granted)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Permissions warning",
"External storage access permission not granted, some files"
" may be inaccessible.");
}
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Permissions warning")
.withMessage ("External storage access permission not granted, some files"
" may be inaccessible.")
.withButton ("OK"),
nullptr);
}); });
} }
@@ -222,9 +218,12 @@ private:
{ {
void operator() (int result) const noexcept void operator() (int result) const noexcept
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"Alert Box",
"Result code: " + String (result));
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Alert Box")
.withMessage ("Result code: " + String (result))
.withButton ("OK"),
nullptr);
} }
}; };
@@ -246,10 +245,14 @@ private:
auto optionIndexChosen = aw.getComboBoxComponent ("option")->getSelectedItemIndex(); auto optionIndexChosen = aw.getComboBoxComponent ("option")->getSelectedItemIndex();
auto text = aw.getTextEditorContents ("text"); auto text = aw.getTextEditorContents ("text");
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Alert Box",
"Result code: " + String (result) + newLine
+ "Option index chosen: " + String (optionIndexChosen) + newLine
+ "Text: " + text);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Alert Box")
.withMessage ("Result code: " + String (result) + newLine
+ "Option index chosen: " + String (optionIndexChosen) + newLine
+ "Text: " + text)
.withButton ("OK"),
nullptr);
} }
DialogsDemo& demo; DialogsDemo& demo;
@@ -259,11 +262,11 @@ private:
{ {
if (type >= plainAlertWindow && type <= questionAlertWindow) if (type >= plainAlertWindow && type <= questionAlertWindow)
{ {
AlertWindow::AlertIconType icon = AlertWindow::NoIcon;
MessageBoxIconType icon = MessageBoxIconType::NoIcon;
if (type == warningAlertWindow) icon = AlertWindow::WarningIcon;
if (type == infoAlertWindow) icon = AlertWindow::InfoIcon;
if (type == questionAlertWindow) icon = AlertWindow::QuestionIcon;
if (type == warningAlertWindow) icon = MessageBoxIconType::WarningIcon;
if (type == infoAlertWindow) icon = MessageBoxIconType::InfoIcon;
if (type == questionAlertWindow) icon = MessageBoxIconType::QuestionIcon;
AlertWindow::showMessageBoxAsync (icon, "This is an AlertWindow", AlertWindow::showMessageBoxAsync (icon, "This is an AlertWindow",
"And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
@@ -271,7 +274,7 @@ private:
} }
else if (type == okCancelAlertWindow) else if (type == okCancelAlertWindow)
{ {
AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, "This is an ok/cancel AlertWindow",
AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon, "This is an ok/cancel AlertWindow",
"And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
{}, {}, {}, {}, {}, {},
ModalCallbackFunction::create (AlertBoxResultChosen{})); ModalCallbackFunction::create (AlertBoxResultChosen{}));
@@ -291,7 +294,7 @@ private:
{ {
asyncAlertWindow = std::make_unique<AlertWindow> ("AlertWindow demo..", asyncAlertWindow = std::make_unique<AlertWindow> ("AlertWindow demo..",
"This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.", "This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.",
AlertWindow::QuestionIcon);
MessageBoxIconType::QuestionIcon);
asyncAlertWindow->addTextEditor ("text", "enter some text here", "text field:"); asyncAlertWindow->addTextEditor ("text", "enter some text here", "text field:");
asyncAlertWindow->addComboBox ("option", { "option 1", "option 2", "option 3", "option 4" }, "some options"); asyncAlertWindow->addComboBox ("option", { "option 1", "option 2", "option 3", "option 4" }, "some options");
@@ -326,9 +329,12 @@ private:
chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName()
: result.toString (false)) << "\n"; : result.toString (false)) << "\n";
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + chosen);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("File Chooser...")
.withMessage ("You picked: " + chosen)
.withButton ("OK"),
nullptr);
}); });
} }
else if (type == loadWithPreviewChooser) else if (type == loadWithPreviewChooser)
@@ -349,9 +355,12 @@ private:
chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName()
: result.toString (false)) << "\n"; : result.toString (false)) << "\n";
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + chosen);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("File Chooser...")
.withMessage ("You picked: " + chosen)
.withButton ("OK"),
nullptr);
}, },
&imagePreview); &imagePreview);
} }
@@ -401,9 +410,12 @@ private:
} }
#endif #endif
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + name);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("File Chooser...")
.withMessage ("You picked: " + name)
.withButton ("OK"),
nullptr);
}); });
} }
else if (type == directoryChooser) else if (type == directoryChooser)
@@ -420,9 +432,12 @@ private:
auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName() auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName()
: result.toString (true); : result.toString (true);
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"File Chooser...",
"You picked: " + name);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("File Chooser...")
.withMessage ("You picked: " + name)
.withButton ("OK"),
nullptr);
}); });
} }
} }
@@ -433,8 +448,12 @@ private:
{ {
auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")");
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Sharing Text Result",
"Sharing text finished\nwith " + resultString);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Sharing Text Result")
.withMessage ("Sharing text finished\nwith " + resultString)
.withButton ("OK"),
nullptr);
}); });
} }
else if (type == shareFile) else if (type == shareFile)
@@ -454,9 +473,12 @@ private:
{ {
auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")");
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"Sharing Files Result",
"Sharing files finished\nwith " + resultString);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Sharing Files Result")
.withMessage ("Sharing files finished\nwith " + resultString)
.withButton ("OK"),
nullptr);
}); });
} }
@@ -480,8 +502,12 @@ private:
String resultString = success ? String ("success") String resultString = success ? String ("success")
: ("failure\n (error: " + error + ")"); : ("failure\n (error: " + error + ")");
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Sharing Images Result",
"Sharing images finished\nwith " + resultString);
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Sharing Images Result")
.withMessage ("Sharing images finished\nwith " + resultString)
.withButton ("OK"),
nullptr);
}); });
} }
} }


+ 1
- 1
examples/GUI/PropertiesDemo.h View File

@@ -61,7 +61,7 @@ public:
void buttonClicked() override void buttonClicked() override
{ {
++counter; ++counter;
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Action Button Pressed",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Action Button Pressed",
"Pressing this type of property component can trigger an action such as showing an alert window!"); "Pressing this type of property component can trigger an action such as showing an alert window!");
refresh(); refresh();
} }


+ 6
- 6
examples/GUI/VideoDemo.h View File

@@ -134,7 +134,7 @@ private:
} }
else else
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Couldn't load the file!", "Couldn't load the file!",
result.getErrorMessage()); result.getErrorMessage());
} }
@@ -354,7 +354,7 @@ public:
{ {
if (! granted) if (! granted)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Permissions warning", "Permissions warning",
"External storage access permission not granted, some files" "External storage access permission not granted, some files"
" may be inaccessible."); " may be inaccessible.");
@@ -503,7 +503,7 @@ private:
void askIfUseNativeControls (const URL& url) void askIfUseNativeControls (const URL& url)
{ {
auto* aw = new AlertWindow ("Choose viewer type", {}, AlertWindow::NoIcon);
auto* aw = new AlertWindow ("Choose viewer type", {}, MessageBoxIconType::NoIcon);
aw->addButton ("Yes", 1, KeyPress (KeyPress::returnKey)); aw->addButton ("Yes", 1, KeyPress (KeyPress::returnKey));
aw->addButton ("No", 0, KeyPress (KeyPress::escapeKey)); aw->addButton ("No", 0, KeyPress (KeyPress::escapeKey));
@@ -559,7 +559,7 @@ private:
void showVideoUrlPrompt() void showVideoUrlPrompt()
{ {
auto* aw = new AlertWindow ("Enter URL for video to load", {}, AlertWindow::NoIcon);
auto* aw = new AlertWindow ("Enter URL for video to load", {}, MessageBoxIconType::NoIcon);
aw->addButton ("OK", 1, KeyPress (KeyPress::returnKey)); aw->addButton ("OK", 1, KeyPress (KeyPress::returnKey));
aw->addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey)); aw->addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey));
@@ -596,7 +596,7 @@ private:
} }
else else
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Couldn't load the file!", "Couldn't load the file!",
result.getErrorMessage()); result.getErrorMessage());
} }
@@ -677,7 +677,7 @@ private:
void errorOccurred (const String& errorMessage) void errorOccurred (const String& errorMessage)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"An error has occurred", "An error has occurred",
errorMessage + ", video will be unloaded."); errorMessage + ", video will be unloaded.");


+ 2
- 2
examples/Utilities/InAppPurchasesDemo.h View File

@@ -156,7 +156,7 @@ private:
voiceProduct.purchasePrice = "In-App purchases unavailable"; voiceProduct.purchasePrice = "In-App purchases unavailable";
} }
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"In-app purchase is unavailable!", "In-app purchase is unavailable!",
"In-App purchases are not available. This either means you are trying " "In-App purchases are not available. This either means you are trying "
"to use IAP on a platform that does not support IAP or you haven't setup " "to use IAP on a platform that does not support IAP or you haven't setup "
@@ -178,7 +178,7 @@ private:
} }
} }
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Your credit card will be charged!", "Your credit card will be charged!",
"You are running the sample code for JUCE In-App purchases. " "You are running the sample code for JUCE In-App purchases. "
"Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!", "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!",


+ 5
- 5
examples/Utilities/OSCDemo.h View File

@@ -222,7 +222,7 @@ private:
//============================================================================== //==============================================================================
void showConnectionErrorMessage (const String& messageText) void showConnectionErrorMessage (const String& messageText)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Connection error", "Connection error",
messageText, messageText,
"OK"); "OK");
@@ -273,7 +273,7 @@ private:
void showConnectionErrorMessage (const String& messageText) void showConnectionErrorMessage (const String& messageText)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Connection error", "Connection error",
messageText, messageText,
"OK"); "OK");
@@ -403,7 +403,7 @@ private:
//============================================================================== //==============================================================================
void handleConnectError (int failedPort) void handleConnectError (int failedPort)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"OSC Connection error", "OSC Connection error",
"Error: could not connect to port " + String (failedPort), "Error: could not connect to port " + String (failedPort),
"OK"); "OK");
@@ -412,7 +412,7 @@ private:
//============================================================================== //==============================================================================
void handleDisconnectError() void handleDisconnectError()
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Unknown error", "Unknown error",
"An unknown error occurred while trying to disconnect from UDP port.", "An unknown error occurred while trying to disconnect from UDP port.",
"OK"); "OK");
@@ -421,7 +421,7 @@ private:
//============================================================================== //==============================================================================
void handleInvalidPortNumberEntered() void handleInvalidPortNumberEntered()
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Invalid port number", "Invalid port number",
"Error: you have entered an invalid UDP port number.", "Error: you have entered an invalid UDP port number.",
"OK"); "OK");


+ 72
- 44
examples/Utilities/PushNotificationsDemo.h View File

@@ -194,7 +194,11 @@ public:
if (token.isEmpty()) if (token.isEmpty())
showRemoteInstructions(); showRemoteInstructions();
else else
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Device token", token);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Device token")
.withMessage (token),
nullptr);
}; };
#if JUCE_ANDROID #if JUCE_ANDROID
@@ -308,11 +312,11 @@ private:
String requiredFields = "all required fields"; String requiredFields = "all required fields";
#endif #endif
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Incorrect notifications setup",
"Please make sure that "
+ requiredFields + " are set.");
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Incorrect notifications setup")
.withMessage ("Please make sure that " + requiredFields + " are set."),
nullptr);
return; return;
} }
@@ -559,11 +563,13 @@ private:
{ {
ignoreUnused (isLocalNotification); ignoreUnused (isLocalNotification);
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Received notification",
"ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Received notification")
.withMessage ("ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body),
nullptr);
} }
void handleNotificationAction (bool isLocalNotification, void handleNotificationAction (bool isLocalNotification,
@@ -573,24 +579,28 @@ private:
{ {
ignoreUnused (isLocalNotification); ignoreUnused (isLocalNotification);
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Received notification action",
"ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body
+ ", action: " + actionIdentifier
+ ", optionalResponse: " + optionalResponse);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Received notification action")
.withMessage ("ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body
+ ", action: " + actionIdentifier
+ ", optionalResponse: " + optionalResponse),
nullptr);
PushNotifications::getInstance()->removeDeliveredNotification (n.identifier); PushNotifications::getInstance()->removeDeliveredNotification (n.identifier);
} }
void localNotificationDismissedByUser (const PushNotifications::Notification& n) override void localNotificationDismissedByUser (const PushNotifications::Notification& n) override
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Notification dismissed by a user",
"ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Notification dismissed by a user")
.withMessage ("ID: " + n.identifier
+ ", title: " + n.title
+ ", body: " + n.body),
nullptr);
} }
void deliveredNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override void deliveredNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override
@@ -600,7 +610,11 @@ private:
for (auto& n : notifs) for (auto& n : notifs)
text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), ";
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Received notification list", text);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Received notification list")
.withMessage (text),
nullptr);
} }
void pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override void pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override
@@ -610,37 +624,49 @@ private:
for (auto& n : notifs) for (auto& n : notifs)
text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), ";
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Pending notification list", text);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Pending notification list")
.withMessage (text),
nullptr);
} }
void deviceTokenRefreshed (const String& token) override void deviceTokenRefreshed (const String& token) override
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Device token refreshed",
token);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Device token refreshed")
.withMessage (token),
nullptr);
} }
#if JUCE_ANDROID #if JUCE_ANDROID
void remoteNotificationsDeleted() override void remoteNotificationsDeleted() override
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Remote notifications deleted",
"Some of the pending messages were removed!");
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Remote notifications deleted")
.withMessage ("Some of the pending messages were removed!"),
nullptr);
} }
void upstreamMessageSent (const String& messageId) override void upstreamMessageSent (const String& messageId) override
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Upstream message sent",
"Message id: " + messageId);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Upstream message sent")
.withMessage ("Message id: " + messageId),
nullptr);
} }
void upstreamMessageSendingError (const String& messageId, const String& error) override void upstreamMessageSendingError (const String& messageId, const String& error) override
{ {
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Upstream message sending error",
"Message id: " + messageId
+ "\nerror: " + error);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Upstream message sending error")
.withMessage ("Message id: " + messageId
+ "\nerror: " + error),
nullptr);
} }
static Array<PushNotifications::Channel> getAndroidChannels() static Array<PushNotifications::Channel> getAndroidChannels()
@@ -1191,12 +1217,14 @@ private:
static void showRemoteInstructions() static void showRemoteInstructions()
{ {
#if JUCE_IOS || JUCE_MAC #if JUCE_IOS || JUCE_MAC
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Remote Notifications instructions",
"In order to be able to test remote notifications "
"ensure that the app is signed and that you register "
"the bundle ID for remote notifications in "
"Apple Developer Center.");
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Remote Notifications instructions")
.withMessage ("In order to be able to test remote notifications "
"ensure that the app is signed and that you register "
"the bundle ID for remote notifications in "
"Apple Developer Center."),
nullptr);
#endif #endif
} }


+ 1
- 1
extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp View File

@@ -98,7 +98,7 @@ void PluginGraph::addPluginCallback (std::unique_ptr<AudioPluginInstance> instan
{ {
if (instance == nullptr) if (instance == nullptr)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Couldn't create plugin"), TRANS("Couldn't create plugin"),
error); error);
} }


+ 2
- 2
extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp View File

@@ -222,7 +222,7 @@ File NewProjectWizard::getLastWizardFolder()
static void displayFailedFilesMessage (const StringArray& failedFiles) static void displayFailedFilesMessage (const StringArray& failedFiles)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Errors in Creating Project!"), TRANS("Errors in Creating Project!"),
TRANS("The following files couldn't be written:") TRANS("The following files couldn't be written:")
+ "\n\n" + "\n\n"
@@ -244,7 +244,7 @@ static void prepareDirectory (const File& targetFolder, Callback&& callback)
} }
else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder)) else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
{ {
AlertWindow::showOkCancelBox (AlertWindow::InfoIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::InfoIcon,
TRANS("New JUCE Project"), TRANS("New JUCE Project"),
TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName()) TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName())
+ TRANS("This folder isn't empty - are you sure you want to create the project there?") + TRANS("This folder isn't empty - are you sure you want to create the project there?")


+ 2
- 2
extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h View File

@@ -122,7 +122,7 @@ private:
if (postStrings.size() != preStrings.size()) if (postStrings.size() != preStrings.size())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Error"), TRANS("Error"),
TRANS("The pre- and post-translation text doesn't match!\n\n" TRANS("The pre- and post-translation text doesn't match!\n\n"
"Perhaps it got mangled by the translator?")); "Perhaps it got mangled by the translator?"));
@@ -138,7 +138,7 @@ private:
if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject()) if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject())
setPreTranslationText (TranslationHelpers::getPreTranslationText (*project)); setPreTranslationText (TranslationHelpers::getPreTranslationText (*project));
else else
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Translation Tool",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool",
"This will only work when you have a project open!"); "This will only work when you have a project open!");
} }


+ 3
- 3
extras/Projucer/Source/Application/jucer_Application.cpp View File

@@ -835,7 +835,7 @@ void ProjucerApplication::launchDemoRunner()
"Couldn't find a compiled version of the Demo Runner." "Couldn't find a compiled version of the Demo Runner."
" Please compile the Demo Runner project in the JUCE examples directory.", " Please compile the Demo Runner project in the JUCE examples directory.",
"OK", {}, {}, "OK", {}, {},
AlertWindow::WarningIcon, 1,
MessageBoxIconType::WarningIcon, 1,
mainWindowList.getFrontmostWindow (false))); mainWindowList.getFrontmostWindow (false)));
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int) demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int)
{ {
@@ -847,7 +847,7 @@ void ProjucerApplication::launchDemoRunner()
"Couldn't find a compiled version of the Demo Runner." "Couldn't find a compiled version of the Demo Runner."
" Do you want to open the project?", " Do you want to open the project?",
"Open project", "Cancel", {}, "Open project", "Cancel", {},
AlertWindow::QuestionIcon, 2,
MessageBoxIconType::QuestionIcon, 2,
mainWindowList.getFrontmostWindow (false))); mainWindowList.getFrontmostWindow (false)));
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal) demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal)
{ {
@@ -1102,7 +1102,7 @@ void ProjucerApplication::createNewProjectFromClipboard()
{ {
if (errorString.isNotEmpty()) if (errorString.isNotEmpty())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", errorString);
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Error", errorString);
tempFile.deleteFile(); tempFile.deleteFile();
} }
}; };


+ 7
- 7
extras/Projucer/Source/Application/jucer_AutoUpdater.cpp View File

@@ -56,7 +56,7 @@ void LatestVersionCheckerAndUpdater::run()
if (info == nullptr) if (info == nullptr)
{ {
if (! backgroundCheck) if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Update Server Communication Error", "Update Server Communication Error",
"Failed to communicate with the JUCE update server.\n" "Failed to communicate with the JUCE update server.\n"
"Please try again in a few minutes.\n\n" "Please try again in a few minutes.\n\n"
@@ -68,7 +68,7 @@ void LatestVersionCheckerAndUpdater::run()
if (! info->isNewerVersionThanCurrent()) if (! info->isNewerVersionThanCurrent())
{ {
if (! backgroundCheck) if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"No New Version Available", "No New Version Available",
"Your JUCE version is up to date."); "Your JUCE version is up to date.");
return; return;
@@ -109,7 +109,7 @@ void LatestVersionCheckerAndUpdater::run()
} }
if (! backgroundCheck) if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Failed to find any new downloads", "Failed to find any new downloads",
"Please try again in a few minutes."); "Please try again in a few minutes.");
} }
@@ -275,13 +275,13 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version
{ {
if (targetFolder.getChildFile (".git").isDirectory()) if (targetFolder.getChildFile (".git").isDirectory())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Downloading New JUCE Version",
targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version.");
return; return;
} }
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Overwrite Existing JUCE Folder?", "Overwrite Existing JUCE Folder?",
"Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n"
"This will move the existing folder to " + targetFolderPath + "_old.\n\n" "This will move the existing folder to " + targetFolderPath + "_old.\n\n"
@@ -295,7 +295,7 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version
if (targetFolder.exists()) if (targetFolder.exists())
{ {
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Existing File Or Directory", "Existing File Or Directory",
"Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?", "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?",
{}, {},
@@ -388,7 +388,7 @@ private:
result = install (zipData); result = install (zipData);
if (result.failed()) if (result.failed())
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Installation Failed", "Installation Failed",
result.getErrorMessage()); }); result.getErrorMessage()); });
else else


+ 3
- 3
extras/Projucer/Source/Application/jucer_MainWindow.cpp View File

@@ -452,7 +452,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba
if (generatorResult != Result::ok()) if (generatorResult != Result::ok())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.", "PIP Error.",
generatorResult.getErrorMessage()); generatorResult.getErrorMessage());
@@ -464,7 +464,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba
if (! generator->createMainCpp()) if (! generator->createMainCpp())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.", "PIP Error.",
"Failed to create Main.cpp."); "Failed to create Main.cpp.");
@@ -481,7 +481,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba
if (! openedSuccessfully) if (! openedSuccessfully)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.", "PIP Error.",
"Failed to open .jucer file."); "Failed to open .jucer file.");


+ 1
- 1
extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp View File

@@ -176,7 +176,7 @@ void OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Docume
return; return;
} }
AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon,
TRANS("Closing document..."), TRANS("Closing document..."),
TRANS("Do you want to save the changes to \"") TRANS("Do you want to save the changes to \"")
+ doc->getName() + "\"?", + doc->getName() + "\"?",


+ 1
- 1
extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp View File

@@ -658,7 +658,7 @@ void CppCodeEditorComponent::insertComponentClass()
{ {
asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Insert a new Component class"), asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Insert a new Component class"),
TRANS ("Please enter a name for the new class"), TRANS ("Please enter a name for the new class"),
AlertWindow::NoIcon,
MessageBoxIconType::NoIcon,
nullptr); nullptr);
const String classNameField { "Class Name" }; const String classNameField { "Class Name" };


+ 1
- 1
extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp View File

@@ -265,7 +265,7 @@ void ResourceEditorPanel::reloadAll()
failed.add (document.getResources().getResourceNames() [i]); failed.add (document.getResources().getResourceNames() [i]);
if (failed.size() > 0) if (failed.size() > 0)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Reloading resources"), TRANS("Reloading resources"),
TRANS("The following resources couldn't be reloaded from their original files:\n\n") TRANS("The following resources couldn't be reloaded from their original files:\n\n")
+ failed.joinIntoString (", ")); + failed.joinIntoString (", "));


+ 1
- 1
extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp View File

@@ -143,7 +143,7 @@ void BinaryResources::browseForResource (const String& title,
if (! add (name, fc.getResult())) if (! add (name, fc.getResult()))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Adding Resource"), TRANS("Adding Resource"),
TRANS("Failed to load the file!")); TRANS("Failed to load the file!"));


+ 2
- 2
extras/Projucer/Source/Project/Modules/jucer_Modules.cpp View File

@@ -682,14 +682,14 @@ void EnabledModulesList::addModuleOfferingToCopy (const File& f, bool isFromUser
if (! m.isValid()) if (! m.isValid())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Add Module", "This wasn't a valid module folder!"); "Add Module", "This wasn't a valid module folder!");
return; return;
} }
if (isModuleEnabled (m.getID())) if (isModuleEnabled (m.getID()))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Add Module", "The project already contains this module!"); "Add Module", "The project already contains this module!");
return; return;
} }


+ 2
- 2
extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h View File

@@ -90,7 +90,7 @@ public:
safeThis->project.getUndoManagerFor (parent)); safeThis->project.getUndoManagerFor (parent));
}; };
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Delete Exporter", "Delete Exporter",
"Are you sure you want to delete this export target?", "Are you sure you want to delete this export target?",
"", "",
@@ -244,7 +244,7 @@ public:
void deleteItem() override void deleteItem() override
{ {
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Delete Configuration", "Delete Configuration",
"Are you sure you want to delete this configuration?", "Are you sure you want to delete this configuration?",
"", "",


+ 6
- 6
extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h View File

@@ -138,7 +138,7 @@ public:
if (filesToTrash.size() > maxFilesToList) if (filesToTrash.size() > maxFilesToList)
fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files..."; fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files...";
AlertWindow::showYesNoCancelBox (AlertWindow::NoIcon,
AlertWindow::showYesNoCancelBox (MessageBoxIconType::NoIcon,
"Delete Project Items", "Delete Project Items",
"As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n" "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n"
+ fileList, + fileList,
@@ -521,7 +521,7 @@ public:
{ {
if (newName != File::createLegalFileName (newName)) if (newName != File::createLegalFileName (newName))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename", "File Rename",
"That filename contained some illegal characters!"); "That filename contained some illegal characters!");
triggerAsyncRename (item); triggerAsyncRename (item);
@@ -538,7 +538,7 @@ public:
if (correspondingItem.isValid()) if (correspondingItem.isValid())
{ {
AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::NoIcon,
"File Rename", "File Rename",
"Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?", "Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?",
{}, {},
@@ -552,7 +552,7 @@ public:
if (! parent->item.renameFile (newFile)) if (! parent->item.renameFile (newFile))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename", "File Rename",
"Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); "Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!");
return; return;
@@ -560,7 +560,7 @@ public:
if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension()))) if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension())))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename", "File Rename",
"Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); "Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!");
} }
@@ -571,7 +571,7 @@ public:
if (! item.renameFile (newFile)) if (! item.renameFile (newFile))
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename", "File Rename",
"Failed to rename the file!\n\nCheck your file permissions!"); "Failed to rename the file!\n\nCheck your file permissions!");
} }


+ 1
- 1
extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h View File

@@ -378,7 +378,7 @@ private:
{ {
missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID); missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID);
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Adding Missing Dependencies", "Adding Missing Dependencies",
"Couldn't locate some of these modules - you'll need to find their " "Couldn't locate some of these modules - you'll need to find their "
"folders manually and add them to the list."); "folders manually and add them to the list.");


+ 1
- 1
extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp View File

@@ -320,7 +320,7 @@ void ProjectContentComponent::closeDocument()
static void showSaveWarning (OpenDocumentManager::Document* currentDocument) static void showSaveWarning (OpenDocumentManager::Document* currentDocument)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Save failed!"), TRANS("Save failed!"),
TRANS("Couldn't save the file:") TRANS("Couldn't save the file:")
+ "\n" + currentDocument->getFile().getFullPathName()); + "\n" + currentDocument->getFile().getFullPathName());


+ 1
- 1
extras/Projucer/Source/Project/jucer_Project.cpp View File

@@ -407,7 +407,7 @@ void Project::removeDefunctExporters()
if (ProjucerApplication::getApp().isRunningCommandLine) if (ProjucerApplication::getApp().isRunningCommandLine)
std::cout << "WARNING! The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project." << std::endl; std::cout << "WARNING! The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project." << std::endl;
else else
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS (oldExporters[key]), TRANS (oldExporters[key]),
TRANS ("The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project.")); TRANS ("The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project."));


+ 1
- 1
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h View File

@@ -723,7 +723,7 @@ public:
"Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX/RTAS Binary Location\" in the Xcode (OS X) configuration settings.\n\n" "Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX/RTAS Binary Location\" in the Xcode (OS X) configuration settings.\n\n"
"Click 'Update' to remove the script (otherwise your plug-in may not compile correctly)."; "Click 'Update' to remove the script (otherwise your plug-in may not compile correctly).";
if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
if (AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Project settings: " + project.getDocumentTitle(), "Project settings: " + project.getDocumentTitle(),
alertWindowText, "Update", "Cancel", nullptr, nullptr)) alertWindowText, "Update", "Cancel", nullptr, nullptr))
postbuildCommandValue.resetToDefault(); postbuildCommandValue.resetToDefault();


+ 2
- 2
extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp View File

@@ -171,7 +171,7 @@ private:
{ {
asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Create new Component class"), asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Create new Component class"),
TRANS ("Please enter the name for the new class"), TRANS ("Please enter the name for the new class"),
AlertWindow::NoIcon, nullptr);
MessageBoxIconType::NoIcon, nullptr);
asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false); asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false);
asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey)); asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey));
@@ -235,7 +235,7 @@ public:
//============================================================================== //==============================================================================
void NewFileWizard::Type::showFailedToWriteMessage (const File& file) void NewFileWizard::Type::showFailedToWriteMessage (const File& file)
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Failed to Create File!", "Failed to Create File!",
"Couldn't write to the file: " + file.getFullPathName()); "Couldn't write to the file: " + file.getFullPathName());
} }


+ 4
- 4
modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp View File

@@ -388,8 +388,8 @@ public:
PropertiesFile* properties, bool allowPluginsWhichRequireAsynchronousInstantiation, int threads, PropertiesFile* properties, bool allowPluginsWhichRequireAsynchronousInstantiation, int threads,
const String& title, const String& text) const String& title, const String& text)
: owner (plc), formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties), : owner (plc), formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties),
pathChooserWindow (TRANS("Select folders to scan..."), String(), AlertWindow::NoIcon),
progressWindow (title, text, AlertWindow::NoIcon),
pathChooserWindow (TRANS("Select folders to scan..."), String(), MessageBoxIconType::NoIcon),
progressWindow (title, text, MessageBoxIconType::NoIcon),
numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation) numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation)
{ {
FileSearchPath path (formatToScan.getDefaultLocationsToSearch()); FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
@@ -467,7 +467,7 @@ private:
if (isStupidPath (f)) if (isStupidPath (f))
{ {
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS("Plugin Scanning"), TRANS("Plugin Scanning"),
TRANS("If you choose to scan folders that contain non-plugin files, " TRANS("If you choose to scan folders that contain non-plugin files, "
"then scanning may take a long time, and can cause crashes when " "then scanning may take a long time, and can cause crashes when "
@@ -642,7 +642,7 @@ void PluginListComponent::scanFinished (const StringArray& failedFiles)
currentScanner.reset(); // mustn't delete this before using the failed files array currentScanner.reset(); // mustn't delete this before using the failed files array
if (shortNames.size() > 0) if (shortNames.size() > 0)
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
TRANS("Scan complete"), TRANS("Scan complete"),
TRANS("Note that the following files appeared to be plugin files, but failed to load correctly") TRANS("Note that the following files appeared to be plugin files, but failed to load correctly")
+ ":\n\n" + ":\n\n"


+ 1
- 1
modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp View File

@@ -405,7 +405,7 @@ public:
} }
if (error.isNotEmpty()) if (error.isNotEmpty())
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Error when trying to open audio device!"), TRANS("Error when trying to open audio device!"),
error); error);
} }


+ 0
- 21
modules/juce_gui_basics/components/juce_ModalComponentManager.cpp View File

@@ -289,25 +289,4 @@ int ModalComponentManager::runEventLoopForCurrentComponent()
} }
#endif #endif
//==============================================================================
struct LambdaCallback : public ModalComponentManager::Callback
{
LambdaCallback (std::function<void (int)> fn) noexcept : function (fn) {}
void modalStateFinished (int result) override
{
if (function != nullptr)
function (result);
}
std::function<void (int)> function;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback)
};
ModalComponentManager::Callback* ModalCallbackFunction::create (std::function<void (int)> f)
{
return new LambdaCallback (f);
}
} // namespace juce } // namespace juce

+ 15
- 3
modules/juce_gui_basics/components/juce_ModalComponentManager.h View File

@@ -163,14 +163,26 @@ class JUCE_API ModalCallbackFunction
{ {
public: public:
/** This is a utility function to create a ModalComponentManager::Callback that will /** This is a utility function to create a ModalComponentManager::Callback that will
call a lambda function.
call a callable object.
The lambda that you supply must take an integer parameter, which is the result code that
The function that you supply must take an integer parameter, which is the result code that
was returned when the modal component was dismissed. was returned when the modal component was dismissed.
@see ModalComponentManager::Callback @see ModalComponentManager::Callback
*/ */
static ModalComponentManager::Callback* create (std::function<void (int)>);
template <typename CallbackFn>
static ModalComponentManager::Callback* create (CallbackFn&& fn)
{
struct Callable : public ModalComponentManager::Callback
{
explicit Callable (CallbackFn&& f) : fn (std::forward<CallbackFn> (f)) {}
void modalStateFinished (int result) override { fn (result); }
CallbackFn fn;
};
return new Callable (std::forward<CallbackFn> (fn));
}
//============================================================================== //==============================================================================
/** This is a utility function to create a ModalComponentManager::Callback that will /** This is a utility function to create a ModalComponentManager::Callback that will


+ 3
- 3
modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp View File

@@ -194,7 +194,7 @@ void FileChooserDialogBox::okButtonPressed()
&& content->chooserComponent.isSaveMode() && content->chooserComponent.isSaveMode()
&& content->chooserComponent.getSelectedFile(0).exists()) && content->chooserComponent.getSelectedFile(0).exists())
{ {
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS("File already exists"), TRANS("File already exists"),
TRANS("There's already a file called: FLNM") TRANS("There's already a file called: FLNM")
.replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName()) .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
@@ -229,7 +229,7 @@ void FileChooserDialogBox::createNewFolder()
{ {
auto* aw = new AlertWindow (TRANS("New Folder"), auto* aw = new AlertWindow (TRANS("New Folder"),
TRANS("Please enter the name for the folder"), TRANS("Please enter the name for the folder"),
AlertWindow::NoIcon, this);
MessageBoxIconType::NoIcon, this);
aw->addTextEditor ("Folder Name", String(), String(), false); aw->addTextEditor ("Folder Name", String(), String(), false);
aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey)); aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey));
@@ -251,7 +251,7 @@ void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialo
auto parent = content->chooserComponent.getRoot(); auto parent = content->chooserComponent.getRoot();
if (! parent.getChildFile (name).createDirectory()) if (! parent.getChildFile (name).createDirectory())
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("New Folder"), TRANS ("New Folder"),
TRANS ("Couldn't create the folder!")); TRANS ("Couldn't create the folder!"));


+ 2
- 0
modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -66,6 +66,7 @@
#include <windowsx.h> #include <windowsx.h>
#include <vfw.h> #include <vfw.h>
#include <commdlg.h> #include <commdlg.h>
#include <commctrl.h>
#if ! JUCE_MINGW #if ! JUCE_MINGW
#include <UIAutomation.h> #include <UIAutomation.h>
@@ -82,6 +83,7 @@
#elif ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES #elif ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment(lib, "vfw32.lib") #pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "imm32.lib") #pragma comment(lib, "imm32.lib")
#pragma comment(lib, "comctl32.lib")
#if JUCE_OPENGL #if JUCE_OPENGL
#pragma comment(lib, "OpenGL32.Lib") #pragma comment(lib, "OpenGL32.Lib")


+ 1
- 0
modules/juce_gui_basics/juce_gui_basics.h View File

@@ -258,6 +258,7 @@ namespace juce
#include "misc/juce_JUCESplashScreen.h" #include "misc/juce_JUCESplashScreen.h"
#include "widgets/juce_TreeView.h" #include "widgets/juce_TreeView.h"
#include "windows/juce_TopLevelWindow.h" #include "windows/juce_TopLevelWindow.h"
#include "windows/juce_MessageBoxOptions.h"
#include "windows/juce_AlertWindow.h" #include "windows/juce_AlertWindow.h"
#include "windows/juce_CallOutBox.h" #include "windows/juce_CallOutBox.h"
#include "windows/juce_ComponentPeer.h" #include "windows/juce_ComponentPeer.h"


+ 5
- 5
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -407,7 +407,7 @@ void LookAndFeel_V2::drawDrawableButton (Graphics& g, DrawableButton& button,
//============================================================================== //==============================================================================
AlertWindow* LookAndFeel_V2::createAlertWindow (const String& title, const String& message, AlertWindow* LookAndFeel_V2::createAlertWindow (const String& title, const String& message,
const String& button1, const String& button2, const String& button3, const String& button1, const String& button2, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) int numButtons, Component* associatedComponent)
{ {
AlertWindow* aw = new AlertWindow (title, message, iconType, associatedComponent); AlertWindow* aw = new AlertWindow (title, message, iconType, associatedComponent);
@@ -457,13 +457,13 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert,
const Rectangle<int> iconRect (iconSize / -10, iconSize / -10, const Rectangle<int> iconRect (iconSize / -10, iconSize / -10,
iconSize, iconSize); iconSize, iconSize);
if (alert.getAlertType() != AlertWindow::NoIcon)
if (alert.getAlertType() != MessageBoxIconType::NoIcon)
{ {
Path icon; Path icon;
uint32 colour; uint32 colour;
char character; char character;
if (alert.getAlertType() == AlertWindow::WarningIcon)
if (alert.getAlertType() == MessageBoxIconType::WarningIcon)
{ {
colour = 0x55ff5555; colour = 0x55ff5555;
character = '!'; character = '!';
@@ -476,8 +476,8 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert,
} }
else else
{ {
colour = alert.getAlertType() == AlertWindow::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900;
character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?';
colour = alert.getAlertType() == MessageBoxIconType::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900;
character = alert.getAlertType() == MessageBoxIconType::InfoIcon ? 'i' : '?';
icon.addEllipse (iconRect.toFloat()); icon.addEllipse (iconRect.toFloat());
} }


+ 1
- 1
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h View File

@@ -67,7 +67,7 @@ public:
const String& button1, const String& button1,
const String& button2, const String& button2,
const String& button3, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) override; int numButtons, Component* associatedComponent) override;
void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override;


+ 4
- 4
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp View File

@@ -385,7 +385,7 @@ void LookAndFeel_V4::changeToggleButtonWidthToFitText (ToggleButton& button)
//============================================================================== //==============================================================================
AlertWindow* LookAndFeel_V4::createAlertWindow (const String& title, const String& message, AlertWindow* LookAndFeel_V4::createAlertWindow (const String& title, const String& message,
const String& button1, const String& button2, const String& button3, const String& button1, const String& button2, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) int numButtons, Component* associatedComponent)
{ {
auto boundsOffset = 50; auto boundsOffset = 50;
@@ -429,13 +429,13 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert,
Rectangle<int> iconRect (iconSize / -10, iconSize / -10, Rectangle<int> iconRect (iconSize / -10, iconSize / -10,
iconSize, iconSize); iconSize, iconSize);
if (alert.getAlertType() != AlertWindow::NoIcon)
if (alert.getAlertType() != MessageBoxIconType::NoIcon)
{ {
Path icon; Path icon;
char character; char character;
uint32 colour; uint32 colour;
if (alert.getAlertType() == AlertWindow::WarningIcon)
if (alert.getAlertType() == MessageBoxIconType::WarningIcon)
{ {
character = '!'; character = '!';
@@ -449,7 +449,7 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert,
else else
{ {
colour = Colour (0xff00b0b9).withAlpha (0.4f).getARGB(); colour = Colour (0xff00b0b9).withAlpha (0.4f).getARGB();
character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?';
character = alert.getAlertType() == MessageBoxIconType::InfoIcon ? 'i' : '?';
icon.addEllipse (iconRect.toFloat()); icon.addEllipse (iconRect.toFloat());
} }


+ 1
- 1
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.h View File

@@ -130,7 +130,7 @@ public:
const String& button1, const String& button1,
const String& button2, const String& button2,
const String& button3, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) override; int numButtons, Component* associatedComponent) override;
void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override;


+ 66
- 39
modules/juce_gui_basics/native/juce_android_Windowing.cpp View File

@@ -1226,8 +1226,8 @@ DECLARE_JNI_CLASS (AndroidDialogOnClickListener, "android/content/DialogInterfac
class DialogListener : public juce::AndroidInterfaceImplementer class DialogListener : public juce::AndroidInterfaceImplementer
{ {
public: public:
DialogListener (ModalComponentManager::Callback* callbackToUse, int resultToUse)
: callback (callbackToUse), result (resultToUse)
DialogListener (std::shared_ptr<ModalComponentManager::Callback> callbackToUse, int resultToUse)
: callback (std::move (callbackToUse)), result (resultToUse)
{} {}
void onResult (jobject dialog) void onResult (jobject dialog)
@@ -1257,46 +1257,44 @@ private:
return AndroidInterfaceImplementer::invoke (proxy, method, args); return AndroidInterfaceImplementer::invoke (proxy, method, args);
} }
std::unique_ptr<ModalComponentManager::Callback> callback;
std::shared_ptr<ModalComponentManager::Callback> callback;
int result; int result;
}; };
//============================================================================== //==============================================================================
static void createAndroidDialog (const String& title, const String& message,
ModalComponentManager::Callback* callback,
const String& positiveButton = {}, const String& negativeButton = {},
const String& neutralButton = {})
static void createAndroidDialog (const MessageBoxOptions& opts,
std::unique_ptr<ModalComponentManager::Callback> callback)
{ {
auto* env = getEnv(); auto* env = getEnv();
LocalRef<jobject> builder (env->NewObject (AndroidAlertDialogBuilder, AndroidAlertDialogBuilder.construct, getMainActivity().get())); LocalRef<jobject> builder (env->NewObject (AndroidAlertDialogBuilder, AndroidAlertDialogBuilder.construct, getMainActivity().get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setTitle, javaString (title).get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setMessage, javaString (message).get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setTitle, javaString (opts.getTitle()).get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setMessage, javaString (opts.getMessage()).get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setCancelable, true)); builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setCancelable, true));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setOnCancelListener,
CreateJavaInterface (new DialogListener (callback, 0),
"android/content/DialogInterface$OnCancelListener").get()));
std::shared_ptr<ModalComponentManager::Callback> sharedCallback (std::move (callback));
auto positiveButtonText = positiveButton.isEmpty() ? String ("OK") : positiveButton;
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setOnCancelListener,
CreateJavaInterface (new DialogListener (sharedCallback, 0),
"android/content/DialogInterface$OnCancelListener").get()));
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setPositiveButton, builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setPositiveButton,
javaString (positiveButtonText).get(),
CreateJavaInterface (new DialogListener (callback, positiveButton.isEmpty() ? 0 : 1),
"android/content/DialogInterface$OnClickListener").get()));
javaString (opts.getButtonText (0)).get(),
CreateJavaInterface (new DialogListener (sharedCallback, 0),
"android/content/DialogInterface$OnClickListener").get()));
if (negativeButton.isNotEmpty())
if (opts.getButtonText (1).isNotEmpty())
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton, builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton,
javaString (negativeButton).get(),
CreateJavaInterface (new DialogListener (callback, neutralButton.isEmpty() ? 0 : 2),
"android/content/DialogInterface$OnClickListener").get()));
javaString (opts.getButtonText (1)).get(),
CreateJavaInterface (new DialogListener (sharedCallback, 1),
"android/content/DialogInterface$OnClickListener").get()));
if (neutralButton.isNotEmpty())
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton,
javaString (neutralButton).get(),
CreateJavaInterface (new DialogListener (callback, 0),
"android/content/DialogInterface$OnClickListener").get()));
if (opts.getButtonText (2).isNotEmpty())
builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNeutralButton,
javaString (opts.getButtonText (2)).get(),
CreateJavaInterface (new DialogListener (sharedCallback, 2),
"android/content/DialogInterface$OnClickListener").get()));
LocalRef<jobject> dialog (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.create)); LocalRef<jobject> dialog (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.create));
@@ -1315,47 +1313,76 @@ static void createAndroidDialog (const String& title, const String& message,
env->CallVoidMethod (window.get(), AndroidWindow.clearFlags, FLAG_NOT_FOCUSABLE); env->CallVoidMethod (window.get(), AndroidWindow.clearFlags, FLAG_NOT_FOCUSABLE);
} }
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
createAndroidDialog (title, message, callback);
showAsync (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK")),
AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox));
} }
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
jassert (callback != nullptr); // on android, all alerts must be non-modal!!
showAsync (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withButton (TRANS("Cancel")),
AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel));
createAndroidDialog (title, message, callback, "OK", "Cancel");
return false; return false;
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
jassert (callback != nullptr); // on android, all alerts must be non-modal!!
showAsync (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No"))
.withButton (TRANS("Cancel")),
AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel));
createAndroidDialog (title, message, callback, "Yes", "No", "Cancel");
return 0; return 0;
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
const String& title, const String& message,
Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback)
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message,
Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback)
{ {
jassert (callback != nullptr); // on android, all alerts must be non-modal!!
showAsync (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No")),
AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel));
createAndroidDialog (title, message, callback, "Yes", "No");
return 0; return 0;
} }
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback)
{
createAndroidDialog (options, std::unique_ptr<ModalComponentManager::Callback> (callback));
}
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
}
//============================================================================== //==============================================================================
static bool androidScreenSaverEnabled = true; static bool androidScreenSaverEnabled = true;


+ 97
- 57
modules/juce_gui_basics/native/juce_ios_Windowing.mm View File

@@ -437,19 +437,18 @@ void LookAndFeel::playAlertSound()
class iOSMessageBox class iOSMessageBox
{ {
public: public:
iOSMessageBox (const String& title, const String& message,
NSString* button1, NSString* button2, NSString* button3,
ModalComponentManager::Callback* cb, const bool async)
: result (0), resultReceived (false), callback (cb), isAsync (async)
iOSMessageBox (const MessageBoxOptions& opts, std::unique_ptr<ModalComponentManager::Callback>&& cb)
: callback (std::move (cb))
{ {
if (currentlyFocusedPeer != nullptr) if (currentlyFocusedPeer != nullptr)
{ {
UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title)
message: juceStringToNS (message)
UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (opts.getTitle())
message: juceStringToNS (opts.getMessage())
preferredStyle: UIAlertControllerStyleAlert]; preferredStyle: UIAlertControllerStyleAlert];
addButton (alert, button1, 0);
addButton (alert, button2, 1);
addButton (alert, button3, 2);
addButton (alert, opts.getButtonText (0));
addButton (alert, opts.getButtonText (1));
addButton (alert, opts.getButtonText (2));
[currentlyFocusedPeer->controller presentViewController: alert [currentlyFocusedPeer->controller presentViewController: alert
animated: YES animated: YES
@@ -469,105 +468,146 @@ public:
JUCE_AUTORELEASEPOOL JUCE_AUTORELEASEPOOL
{ {
while (! resultReceived)
while (result < 0)
[[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
} }
return result; return result;
} }
void buttonClicked (const int buttonIndex) noexcept
void buttonClicked (int buttonIndex) noexcept
{ {
result = buttonIndex;
resultReceived = true;
if (callback != nullptr) if (callback != nullptr)
callback->modalStateFinished (result);
callback->modalStateFinished (buttonIndex);
if (isAsync)
delete this;
delete this;
} }
private: private:
int result;
bool resultReceived;
std::unique_ptr<ModalComponentManager::Callback> callback;
const bool isAsync;
void addButton (UIAlertController* alert, NSString* text, int index)
void addButton (UIAlertController* alert, const String& text)
{ {
if (text != nil)
[alert addAction: [UIAlertAction actionWithTitle: text
if (! text.isEmpty())
{
const auto index = [[alert actions] count];
[alert addAction: [UIAlertAction actionWithTitle: juceStringToNS (text)
style: UIAlertActionStyleDefault style: UIAlertActionStyleDefault
handler: ^(UIAlertAction*) { this->buttonClicked (index); }]];
handler: ^(UIAlertAction*) { this->buttonClicked ((int) index); }]];
}
} }
int result = -1;
std::unique_ptr<ModalComponentManager::Callback> callback;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
}; };
//============================================================================== //==============================================================================
static int showDialog (const MessageBoxOptions& options,
std::unique_ptr<ModalComponentManager::Callback> callback,
Async async)
{
#if JUCE_MODAL_LOOPS_PERMITTED
if (async == Async::no)
{
JUCE_AUTORELEASEPOOL
{
iOSMessageBox messageBox (options, std::move (callback));
return messageBox.getResult();
}
}
#endif
ignoreUnused (async);
new iOSMessageBox (options, std::move (callback));
return 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/) Component* /*associatedComponent*/)
{ {
JUCE_AUTORELEASEPOOL
{
iOSMessageBox mb (title, message, @"OK", nil, nil, nullptr, false);
ignoreUnused (mb.getResult());
}
showDialog (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK")),
nullptr, Async::no);
}
int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
{
return showDialog (options, nullptr, Async::no);
} }
#endif #endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
new iOSMessageBox (title, message, @"OK", nil, nil, callback, true);
showDialog (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)),
Async::yes);
} }
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"OK",
nil, callback, callback != nullptr));
if (callback == nullptr)
return mb->getResult() == 1;
mb.release();
return false;
return showDialog (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withButton (TRANS("Cancel")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no) == 1;
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"Yes", @"No", callback, callback != nullptr));
if (callback == nullptr)
return mb->getResult();
mb.release();
return 0;
return showDialog (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No"))
.withButton (TRANS("Cancel")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)),
callback != nullptr ? Async::yes : Async::no);
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"No", @"Yes", nil, callback, callback != nullptr));
return showDialog (MessageBoxOptions()
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no);
}
if (callback == nullptr)
return mb->getResult();
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback)
{
showDialog (options, rawToUniquePtr (callback), Async::yes);
}
mb.release();
return 0;
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
} }
//============================================================================== //==============================================================================


+ 89
- 7
modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -654,16 +654,86 @@ void LookAndFeel::playAlertSound()
} }
//============================================================================== //==============================================================================
static int showDialog (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback,
Async async)
{
const auto dummyCallback = [] (int) {};
switch (options.getNumButtons())
{
case 2:
{
if (async == Async::yes && callback == nullptr)
callback = ModalCallbackFunction::create (dummyCallback);
return AlertWindow::showOkCancelBox (options.getIconType(),
options.getTitle(),
options.getMessage(),
options.getButtonText (0),
options.getButtonText (1),
options.getAssociatedComponent(),
callback) ? 1 : 0;
}
case 3:
{
if (async == Async::yes && callback == nullptr)
callback = ModalCallbackFunction::create (dummyCallback);
return AlertWindow::showYesNoCancelBox (options.getIconType(),
options.getTitle(),
options.getMessage(),
options.getButtonText (0),
options.getButtonText (1),
options.getButtonText (2),
options.getAssociatedComponent(),
callback);
}
case 1:
default:
break;
}
#if JUCE_MODAL_LOOPS_PERMITTED
if (async == Async::no)
{
AlertWindow::showMessageBox (options.getIconType(),
options.getTitle(),
options.getMessage(),
options.getButtonText (0),
options.getAssociatedComponent());
}
else
#endif
{
AlertWindow::showMessageBoxAsync (options.getIconType(),
options.getTitle(),
options.getMessage(),
options.getButtonText (0),
options.getAssociatedComponent(),
callback);
}
return 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component*)
Component* /*associatedComponent*/)
{ {
AlertWindow::showMessageBox (iconType, title, message); AlertWindow::showMessageBox (iconType, title, message);
} }
int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
{
return showDialog (options, nullptr, Async::no);
}
#endif #endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
@@ -671,7 +741,7 @@ void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIcon
AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback); AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback);
} }
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
@@ -679,7 +749,7 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType
return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback); return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback);
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
@@ -688,15 +758,27 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy
associatedComponent, callback); associatedComponent, callback);
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
return AlertWindow::showOkCancelBox (iconType, title, message, TRANS ("Yes"), TRANS ("No"),
return AlertWindow::showOkCancelBox (iconType, title, message, TRANS("Yes"), TRANS("No"),
associatedComponent, callback); associatedComponent, callback);
} }
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback)
{
showDialog (options, callback, Async::yes);
}
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
}
//============================================================================== //==============================================================================
Image juce_createIconForFile (const File&) Image juce_createIconForFile (const File&)
{ {


+ 109
- 53
modules/juce_gui_basics/native/juce_mac_Windowing.mm View File

@@ -35,47 +35,29 @@ void LookAndFeel::playAlertSound()
class OSXMessageBox : private AsyncUpdater class OSXMessageBox : private AsyncUpdater
{ {
public: public:
OSXMessageBox (AlertWindow::AlertIconType type, const String& t, const String& m,
const char* b1, const char* b2, const char* b3,
ModalComponentManager::Callback* c, const bool runAsync)
: iconType (type), title (t), message (m), callback (c),
button1 (b1), button2 (b2), button3 (b3)
OSXMessageBox (const MessageBoxOptions& opts,
std::unique_ptr<ModalComponentManager::Callback>&& c)
: options (opts), callback (std::move (c))
{ {
if (runAsync)
triggerAsyncUpdate();
} }
int getResult() const int getResult() const
{ {
switch (getRawResult()) switch (getRawResult())
{ {
case NSAlertFirstButtonReturn: return 1;
case NSAlertThirdButtonReturn: return 2;
default: return 0;
case NSAlertFirstButtonReturn: return 0;
case NSAlertSecondButtonReturn: return 1;
case NSAlertThirdButtonReturn: return 2;
default: break;
} }
}
static int show (AlertWindow::AlertIconType iconType, const String& title, const String& message,
ModalComponentManager::Callback* callback, const char* b1, const char* b2, const char* b3,
bool runAsync)
{
std::unique_ptr<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message, b1, b2, b3,
callback, runAsync));
if (! runAsync)
return mb->getResult();
mb.release();
jassertfalse;
return 0; return 0;
} }
private:
AlertWindow::AlertIconType iconType;
String title, message;
std::unique_ptr<ModalComponentManager::Callback> callback;
const char* button1;
const char* button2;
const char* button3;
using AsyncUpdater::triggerAsyncUpdate;
private:
void handleAsyncUpdate() override void handleAsyncUpdate() override
{ {
auto result = getResult(); auto result = getResult();
@@ -86,73 +68,147 @@ private:
delete this; delete this;
} }
static void addButton (NSAlert* alert, const String& button)
{
if (! button.isEmpty())
[alert addButtonWithTitle: juceStringToNS (button)];
}
NSInteger getRawResult() const NSInteger getRawResult() const
{ {
NSAlert* alert = [[[NSAlert alloc] init] autorelease]; NSAlert* alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText: juceStringToNS (title)];
[alert setInformativeText: juceStringToNS (message)];
[alert setMessageText: juceStringToNS (options.getTitle())];
[alert setInformativeText: juceStringToNS (options.getMessage())];
[alert setAlertStyle: options.getIconType() == MessageBoxIconType::WarningIcon ? NSAlertStyleCritical
: NSAlertStyleInformational];
[alert setAlertStyle: iconType == AlertWindow::WarningIcon ? NSAlertStyleCritical
: NSAlertStyleInformational];
addButton (alert, button1);
addButton (alert, button2);
addButton (alert, button3);
const auto button1Text = options.getButtonText (0);
addButton (alert, button1Text.isEmpty() ? "OK" : button1Text);
addButton (alert, options.getButtonText (1));
addButton (alert, options.getButtonText (2));
return [alert runModal]; return [alert runModal];
} }
static void addButton (NSAlert* alert, const char* button)
{
if (button != nullptr)
[alert addButtonWithTitle: juceStringToNS (TRANS (button))];
}
MessageBoxOptions options;
std::unique_ptr<ModalComponentManager::Callback> callback;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXMessageBox)
}; };
static int showDialog (const MessageBoxOptions& options,
std::unique_ptr<ModalComponentManager::Callback> callback,
Async async)
{
auto messageBox = std::make_unique<OSXMessageBox> (options, std::move (callback));
#if JUCE_MODAL_LOOPS_PERMITTED
if (async == Async::no)
return messageBox->getResult();
#endif
ignoreUnused (async);
messageBox->triggerAsyncUpdate();
messageBox.release();
return 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/) Component* /*associatedComponent*/)
{ {
OSXMessageBox::show (iconType, title, message, nullptr, "OK", nullptr, nullptr, false);
showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK")),
nullptr,
Async::no);
}
int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
{
return showDialog (options, nullptr, Async::no);
} }
#endif #endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
OSXMessageBox::show (iconType, title, message, callback, "OK", nullptr, nullptr, true);
showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)),
Async::yes);
} }
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
return OSXMessageBox::show (iconType, title, message, callback,
"OK", "Cancel", nullptr, callback != nullptr) == 1;
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withButton (TRANS("Cancel")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no) != 0;
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
return OSXMessageBox::show (iconType, title, message, callback,
"Yes", "Cancel", "No", callback != nullptr);
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No"))
.withButton (TRANS("Cancel")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)),
callback != nullptr ? Async::yes : Async::no);
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* /*associatedComponent*/, Component* /*associatedComponent*/,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
return OSXMessageBox::show (iconType, title, message, callback,
"Yes", "No", nullptr, callback != nullptr);
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No")),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no);
} }
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback)
{
showDialog (options, rawToUniquePtr (callback), Async::yes);
}
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
}
//============================================================================== //==============================================================================
static NSRect getDragRect (NSView* view, NSEvent* event) static NSRect getDragRect (NSView* view, NSEvent* event)


+ 279
- 59
modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -4411,30 +4411,44 @@ bool juce_areThereAnyAlwaysOnTopWindows()
} }
//============================================================================== //==============================================================================
class WindowsMessageBox : public AsyncUpdater
#if JUCE_MSVC
// required to enable the newer dialog box on vista and above
#pragma comment(linker, \
"\"/MANIFESTDEPENDENCY:type='Win32' " \
"name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' " \
"processorArchitecture='*' " \
"publicKeyToken='6595b64144ccf1df' " \
"language='*'\"" \
)
#endif
class WindowsMessageBoxBase : private AsyncUpdater
{ {
public: public:
WindowsMessageBox (AlertWindow::AlertIconType iconType,
const String& boxTitle, const String& m,
Component* associatedComponent, UINT extraFlags,
ModalComponentManager::Callback* cb, const bool runAsync)
: flags (extraFlags | getMessageBoxFlags (iconType)),
owner (getWindowForMessageBox (associatedComponent)),
title (boxTitle), message (m), callback (cb)
WindowsMessageBoxBase (Component* comp,
std::unique_ptr<ModalComponentManager::Callback>&& cb)
: associatedComponent (comp),
callback (std::move (cb))
{ {
if (runAsync)
triggerAsyncUpdate();
} }
int getResult() const
virtual int getResult() = 0;
HWND getParentHWND() const
{ {
const int r = MessageBox (owner, message.toWideCharPointer(), title.toWideCharPointer(), flags);
return (r == IDYES || r == IDOK) ? 1 : (r == IDNO && (flags & 1) != 0 ? 2 : 0);
if (associatedComponent != nullptr)
return (HWND) associatedComponent->getWindowHandle();
return nullptr;
} }
using AsyncUpdater::triggerAsyncUpdate;
private:
void handleAsyncUpdate() override void handleAsyncUpdate() override
{ {
const int result = getResult();
const auto result = getResult();
if (callback != nullptr) if (callback != nullptr)
callback->modalStateFinished (result); callback->modalStateFinished (result);
@@ -4442,97 +4456,303 @@ public:
delete this; delete this;
} }
private:
UINT flags;
HWND owner;
String title, message;
Component::SafePointer<Component> associatedComponent;
std::unique_ptr<ModalComponentManager::Callback> callback; std::unique_ptr<ModalComponentManager::Callback> callback;
static UINT getMessageBoxFlags (AlertWindow::AlertIconType iconType) noexcept
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsMessageBoxBase)
};
class PreVistaMessageBox : public WindowsMessageBoxBase
{
public:
PreVistaMessageBox (const MessageBoxOptions& opts,
UINT extraFlags,
std::unique_ptr<ModalComponentManager::Callback>&& callback)
: WindowsMessageBoxBase (opts.getAssociatedComponent(), std::move (callback)),
flags (extraFlags | getMessageBoxFlags (opts.getIconType())),
title (opts.getTitle()), message (opts.getMessage())
{ {
UINT flags = MB_TASKMODAL | MB_SETFOREGROUND;
}
int getResult() override
{
const auto result = MessageBox (getParentHWND(), message.toWideCharPointer(), title.toWideCharPointer(), flags);
if (result == IDYES || result == IDOK) return 0;
if (result == IDNO && ((flags & 1) != 0)) return 1;
return 2;
}
private:
static UINT getMessageBoxFlags (MessageBoxIconType iconType) noexcept
{
// this window can get lost behind JUCE windows which are set to be alwaysOnTop // this window can get lost behind JUCE windows which are set to be alwaysOnTop
// so if there are any set it to be topmost // so if there are any set it to be topmost
if (juce_areThereAnyAlwaysOnTopWindows())
flags |= MB_TOPMOST;
const auto topmostFlag = juce_areThereAnyAlwaysOnTopWindows() ? MB_TOPMOST : 0;
switch (iconType)
const auto iconFlags = [&]() -> decltype (topmostFlag)
{ {
case AlertWindow::QuestionIcon: flags |= MB_ICONQUESTION; break;
case AlertWindow::WarningIcon: flags |= MB_ICONWARNING; break;
case AlertWindow::InfoIcon: flags |= MB_ICONINFORMATION; break;
case AlertWindow::NoIcon: JUCE_FALLTHROUGH
default: break;
switch (iconType)
{
case MessageBoxIconType::QuestionIcon: return MB_ICONQUESTION;
case MessageBoxIconType::WarningIcon: return MB_ICONWARNING;
case MessageBoxIconType::InfoIcon: return MB_ICONINFORMATION;
case MessageBoxIconType::NoIcon: break;
}
return 0;
}();
return static_cast<UINT> (MB_TASKMODAL | MB_SETFOREGROUND | topmostFlag | iconFlags);
}
const UINT flags;
const String title, message;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreVistaMessageBox)
};
using TaskDialogIndirectFunc = HRESULT (WINAPI*) (const TASKDIALOGCONFIG*, INT*, INT*, BOOL*);
static TaskDialogIndirectFunc taskDialogIndirect = nullptr;
class WindowsTaskDialog : public WindowsMessageBoxBase
{
public:
WindowsTaskDialog (const MessageBoxOptions& opts,
std::unique_ptr<ModalComponentManager::Callback>&& callback)
: WindowsMessageBoxBase (opts.getAssociatedComponent(), std::move (callback)),
iconType (opts.getIconType()),
title (opts.getTitle()), message (opts.getMessage()),
button1 (opts.getButtonText (0)), button2 (opts.getButtonText (1)), button3 (opts.getButtonText (2))
{
}
int getResult() override
{
TASKDIALOGCONFIG config = { 0 };
config.cbSize = sizeof (config);
config.pszWindowTitle = title.toWideCharPointer();
config.pszContent = message.toWideCharPointer();
config.hInstance = (HINSTANCE) Process::getCurrentModuleInstanceHandle();
if (iconType == MessageBoxIconType::QuestionIcon)
{
if (auto* questionIcon = LoadIcon (nullptr, IDI_QUESTION))
{
config.hMainIcon = questionIcon;
config.dwFlags |= TDF_USE_HICON_MAIN;
}
} }
else
{
auto icon = [this]() -> LPWSTR
{
switch (iconType)
{
case MessageBoxIconType::WarningIcon: return TD_WARNING_ICON;
case MessageBoxIconType::InfoIcon: return TD_INFORMATION_ICON;
case MessageBoxIconType::QuestionIcon: JUCE_FALLTHROUGH
case MessageBoxIconType::NoIcon:
break;
}
return nullptr;
}();
return flags;
if (icon != nullptr)
config.pszMainIcon = icon;
}
std::vector<TASKDIALOG_BUTTON> buttons;
for (const auto* buttonText : { &button1, &button2, &button3 })
if (buttonText->isNotEmpty())
buttons.push_back ({ (int) buttons.size(), buttonText->toWideCharPointer() });
config.pButtons = buttons.data();
config.cButtons = (UINT) buttons.size();
int buttonIndex = 0;
taskDialogIndirect (&config, &buttonIndex, nullptr, nullptr);
return buttonIndex;
} }
static HWND getWindowForMessageBox (Component* associatedComponent)
static bool loadTaskDialog()
{ {
return associatedComponent != nullptr ? (HWND) associatedComponent->getWindowHandle() : nullptr;
static bool hasChecked = false;
if (! hasChecked)
{
hasChecked = true;
const auto comctl = "Comctl32.dll";
LoadLibraryA (comctl);
const auto comctlModule = GetModuleHandleA (comctl);
if (comctlModule != nullptr)
taskDialogIndirect = (TaskDialogIndirectFunc) GetProcAddress (comctlModule, "TaskDialogIndirect");
}
return taskDialogIndirect != nullptr;
} }
private:
MessageBoxIconType iconType;
String title, message, button1, button2, button3;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTaskDialog)
}; };
static std::unique_ptr<WindowsMessageBoxBase> createMessageBox (const MessageBoxOptions& options,
std::unique_ptr<ModalComponentManager::Callback> callback)
{
std::unique_ptr<WindowsMessageBoxBase> messageBox;
if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista
&& WindowsTaskDialog::loadTaskDialog())
{
messageBox.reset (new WindowsTaskDialog (options, std::move (callback)));
}
else
{
const auto extraFlags = [&options]
{
const auto numButtons = options.getNumButtons();
if (numButtons == 3)
return MB_YESNOCANCEL;
if (numButtons == 2)
return options.getButtonText (0) == "OK" ? MB_OKCANCEL
: MB_YESNO;
return MB_OK;
}();
messageBox.reset (new PreVistaMessageBox (options, (UINT) extraFlags, std::move (callback)));
}
return messageBox;
}
static int showDialog (const MessageBoxOptions& options,
std::unique_ptr<ModalComponentManager::Callback> callback,
Async async)
{
auto messageBox = createMessageBox (options, std::move (callback));
#if JUCE_MODAL_LOOPS_PERMITTED
if (async == Async::no)
return messageBox->getResult();
#endif
ignoreUnused (async);
messageBox->triggerAsyncUpdate();
messageBox.release();
return 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent) Component* associatedComponent)
{ {
WindowsMessageBox box (iconType, title, message, associatedComponent, MB_OK, nullptr, false);
(void) box.getResult();
showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withAssociatedComponent (associatedComponent),
nullptr,
Async::no);
}
int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
{
return showDialog (options, nullptr, Async::no);
} }
#endif #endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
new WindowsMessageBox (iconType, title, message, associatedComponent, MB_OK, callback, true);
showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)),
Async::yes);
} }
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent,
MB_OKCANCEL, callback, callback != nullptr));
if (callback == nullptr)
return mb->getResult() != 0;
mb.release();
return false;
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("OK"))
.withButton (TRANS("Cancel"))
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no) == 1;
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent,
MB_YESNOCANCEL, callback, callback != nullptr));
if (callback == nullptr)
return mb->getResult();
mb.release();
return 0;
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No"))
.withButton (TRANS("Cancel"))
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)),
callback != nullptr ? Async::yes : Async::no);
} }
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
const String& title, const String& message, const String& title, const String& message,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent,
MB_YESNO, callback, callback != nullptr));
if (callback == nullptr)
return mb->getResult();
return showDialog (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (TRANS("Yes"))
.withButton (TRANS("No"))
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
callback != nullptr ? Async::yes : Async::no);
}
mb.release();
return 0;
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback)
{
showDialog (options, rawToUniquePtr (callback), Async::yes);
}
void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
} }
//============================================================================== //==============================================================================


+ 128
- 69
modules/juce_gui_basics/windows/juce_AlertWindow.cpp View File

@@ -38,7 +38,7 @@ static juce_wchar getDefaultPasswordChar() noexcept
//============================================================================== //==============================================================================
AlertWindow::AlertWindow (const String& title, AlertWindow::AlertWindow (const String& title,
const String& message, const String& message,
AlertIconType iconType,
MessageBoxIconType iconType,
Component* comp) Component* comp)
: TopLevelWindow (title, true), : TopLevelWindow (title, true),
alertIconType (iconType), alertIconType (iconType),
@@ -561,20 +561,21 @@ int AlertWindow::getDesktopWindowStyleFlags() const
return getLookAndFeel().getAlertBoxWindowFlags(); return getLookAndFeel().getAlertBoxWindowFlags();
} }
enum class Async { no, yes };
//============================================================================== //==============================================================================
class AlertWindowInfo class AlertWindowInfo
{ {
public: public:
AlertWindowInfo (const String& t, const String& m, Component* component,
AlertWindow::AlertIconType icon, int numButts,
ModalComponentManager::Callback* cb, bool runModally)
: title (t), message (m), iconType (icon), numButtons (numButts),
associatedComponent (component), callback (cb), modal (runModally)
AlertWindowInfo (const MessageBoxOptions& opts,
std::unique_ptr<ModalComponentManager::Callback>&& cb,
Async showAsync)
: options (opts),
callback (std::move (cb)),
async (showAsync)
{ {
} }
String title, message, button1, button2, button3;
int invoke() const int invoke() const
{ {
MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this); MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
@@ -582,88 +583,153 @@ public:
} }
private: private:
AlertWindow::AlertIconType iconType;
int numButtons, returnValue = 0;
WeakReference<Component> associatedComponent;
ModalComponentManager::Callback* callback;
bool modal;
static void* showCallback (void* userData)
{
static_cast<AlertWindowInfo*> (userData)->show();
return nullptr;
}
void show() void show()
{ {
auto& lf = associatedComponent != nullptr ? associatedComponent->getLookAndFeel()
: LookAndFeel::getDefaultLookAndFeel();
auto* component = options.getAssociatedComponent();
auto& lf = (component != nullptr ? component->getLookAndFeel()
: LookAndFeel::getDefaultLookAndFeel());
std::unique_ptr<AlertWindow> alertBox (lf.createAlertWindow (title, message, button1, button2, button3,
iconType, numButtons, associatedComponent));
std::unique_ptr<AlertWindow> alertBox (lf.createAlertWindow (options.getTitle(), options.getMessage(),
options.getButtonText (0), options.getButtonText (1), options.getButtonText (2),
options.getIconType(), options.getNumButtons(), component));
jassert (alertBox != nullptr); // you have to return one of these! jassert (alertBox != nullptr); // you have to return one of these!
alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows()); alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
if (modal)
{
if (async == Async::no)
returnValue = alertBox->runModalLoop(); returnValue = alertBox->runModalLoop();
}
else else
#endif #endif
{ {
ignoreUnused (modal);
ignoreUnused (async);
alertBox->enterModalState (true, callback, true);
alertBox->enterModalState (true, callback.release(), true);
alertBox.release(); alertBox.release();
} }
} }
static void* showCallback (void* userData)
MessageBoxOptions options;
std::unique_ptr<ModalComponentManager::Callback> callback;
const Async async;
int returnValue = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindowInfo)
};
namespace AlertWindowMappings
{
static int messageBox (int) { return 0; }
static int okCancel (int buttonIndex) { return buttonIndex == 0 ? 1 : 0; }
static int yesNoCancel (int buttonIndex) { return buttonIndex == 2 ? 0 : buttonIndex + 1; }
ModalComponentManager::Callback* getWrappedCallback (ModalComponentManager::Callback* callbackIn,
std::function<int (int)> mapFn)
{ {
static_cast<AlertWindowInfo*> (userData)->show();
return nullptr;
if (callbackIn == nullptr)
return nullptr;
auto wrappedCallback = [innerCallback = rawToUniquePtr (callbackIn), mapFn] (int buttonIndex)
{
innerCallback->modalStateFinished (mapFn (buttonIndex));
};
return ModalCallbackFunction::create (std::move (wrappedCallback));
} }
};
}
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void AlertWindow::showMessageBox (AlertIconType iconType,
void AlertWindow::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& buttonText, const String& buttonText,
Component* associatedComponent) Component* associatedComponent)
{
show (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText)
.withAssociatedComponent (associatedComponent));
}
int AlertWindow::show (const MessageBoxOptions& options)
{
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
return NativeMessageBox::show (options);
AlertWindowInfo info (options, nullptr, Async::no);
return info.invoke();
}
#endif
void AlertWindow::showAsync (const MessageBoxOptions& options, ModalComponentManager::Callback* callback)
{ {
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
{ {
NativeMessageBox::showMessageBox (iconType, title, message, associatedComponent);
NativeMessageBox::showAsync (options, callback);
} }
else else
{ {
AlertWindowInfo info (title, message, associatedComponent, iconType, 1, nullptr, true);
info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText;
AlertWindowInfo info (options, rawToUniquePtr (callback), Async::yes);
info.invoke(); info.invoke();
} }
} }
#endif
void AlertWindow::showMessageBoxAsync (AlertIconType iconType,
void AlertWindow::showAsync (const MessageBoxOptions& options, std::function<void (int)> callback)
{
showAsync (options, ModalCallbackFunction::create (callback));
}
void AlertWindow::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& buttonText, const String& buttonText,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox);
showAsync (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText)
.withAssociatedComponent (associatedComponent),
callback);
}
static int showMaybeAsync (const MessageBoxOptions& options,
std::unique_ptr<ModalComponentManager::Callback> callback)
{
const auto showAsync = (callback != nullptr ? Async::yes
: Async::no);
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
{ {
NativeMessageBox::showMessageBoxAsync (iconType, title, message, associatedComponent, callback);
}
else
{
AlertWindowInfo info (title, message, associatedComponent, iconType, 1, callback, false);
info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText;
#if JUCE_MODAL_LOOPS_PERMITTED
if (showAsync == Async::no)
return NativeMessageBox::show (options);
#endif
info.invoke();
NativeMessageBox::showAsync (options, callback.release());
return false;
} }
AlertWindowInfo info (options, std::move (callback), showAsync);
return info.invoke();
} }
bool AlertWindow::showOkCancelBox (AlertIconType iconType,
bool AlertWindow::showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& button1Text, const String& button1Text,
@@ -672,16 +738,19 @@ bool AlertWindow::showOkCancelBox (AlertIconType iconType,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
return NativeMessageBox::showOkCancelBox (iconType, title, message, associatedComponent, callback);
AlertWindowInfo info (title, message, associatedComponent, iconType, 2, callback, callback == nullptr);
info.button1 = button1Text.isEmpty() ? TRANS("OK") : button1Text;
info.button2 = button2Text.isEmpty() ? TRANS("Cancel") : button2Text;
callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel);
return info.invoke() != 0;
return showMaybeAsync (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (button1Text.isEmpty() ? TRANS("OK") : button1Text)
.withButton (button2Text.isEmpty() ? TRANS("Cancel") : button2Text)
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (callback)) == 1;
} }
int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
int AlertWindow::showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& button1Text, const String& button1Text,
@@ -691,29 +760,19 @@ int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
ModalComponentManager::Callback* callback) ModalComponentManager::Callback* callback)
{ {
if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
return NativeMessageBox::showYesNoCancelBox (iconType, title, message, associatedComponent, callback);
AlertWindowInfo info (title, message, associatedComponent, iconType, 3, callback, callback == nullptr);
info.button1 = button1Text.isEmpty() ? TRANS("Yes") : button1Text;
info.button2 = button2Text.isEmpty() ? TRANS("No") : button2Text;
info.button3 = button3Text.isEmpty() ? TRANS("Cancel") : button3Text;
return info.invoke();
callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel);
return showMaybeAsync (MessageBoxOptions()
.withIconType (iconType)
.withTitle (title)
.withMessage (message)
.withButton (button1Text.isEmpty() ? TRANS("Yes") : button1Text)
.withButton (button2Text.isEmpty() ? TRANS("No") : button2Text)
.withButton (button3Text.isEmpty() ? TRANS("Cancel") : button3Text)
.withAssociatedComponent (associatedComponent),
rawToUniquePtr (callback));
} }
#if JUCE_MODAL_LOOPS_PERMITTED
bool AlertWindow::showNativeDialogBox (const String& title,
const String& bodyText,
bool isOkCancel)
{
if (isOkCancel)
return NativeMessageBox::showOkCancelBox (AlertWindow::NoIcon, title, bodyText);
NativeMessageBox::showMessageBox (AlertWindow::NoIcon, title, bodyText);
return true;
}
#endif
//============================================================================== //==============================================================================
std::unique_ptr<AccessibilityHandler> AlertWindow::createAccessibilityHandler() std::unique_ptr<AccessibilityHandler> AlertWindow::createAccessibilityHandler()
{ {


+ 72
- 34
modules/juce_gui_basics/windows/juce_AlertWindow.h View File

@@ -44,20 +44,6 @@ namespace juce
class JUCE_API AlertWindow : public TopLevelWindow class JUCE_API AlertWindow : public TopLevelWindow
{ {
public: public:
//==============================================================================
/** The type of icon to show in the dialog box. */
enum AlertIconType
{
NoIcon, /**< No icon will be shown on the dialog box. */
QuestionIcon, /**< A question-mark icon, for dialog boxes that need the
user to answer a question. */
WarningIcon, /**< An exclamation mark to indicate that the dialog is a
warning about something and shouldn't be ignored. */
InfoIcon /**< An icon that indicates that the dialog box is just
giving the user some information, which doesn't require
a response from them. */
};
//============================================================================== //==============================================================================
/** Creates an AlertWindow. /** Creates an AlertWindow.
@@ -71,7 +57,7 @@ public:
*/ */
AlertWindow (const String& title, AlertWindow (const String& title,
const String& message, const String& message,
AlertIconType iconType,
MessageBoxIconType iconType,
Component* associatedComponent = nullptr); Component* associatedComponent = nullptr);
/** Destroys the AlertWindow */ /** Destroys the AlertWindow */
@@ -80,7 +66,7 @@ public:
//============================================================================== //==============================================================================
/** Returns the type of alert icon that was specified when the window /** Returns the type of alert icon that was specified when the window
was created. */ was created. */
AlertIconType getAlertType() const noexcept { return alertIconType; }
MessageBoxIconType getAlertType() const noexcept { return alertIconType; }
//============================================================================== //==============================================================================
/** Changes the dialog box's message. /** Changes the dialog box's message.
@@ -226,8 +212,6 @@ public:
bool containsAnyExtraComponents() const; bool containsAnyExtraComponents() const;
//============================================================================== //==============================================================================
// easy-to-use message box functions:
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
/** Shows a dialog box that just has a message and a single button to get rid of it. /** Shows a dialog box that just has a message and a single button to get rid of it.
@@ -244,13 +228,57 @@ public:
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
*/ */
static void JUCE_CALLTYPE showMessageBox (AlertIconType iconType,
static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& buttonText = String(), const String& buttonText = String(),
Component* associatedComponent = nullptr); Component* associatedComponent = nullptr);
/** Shows a dialog box using the specified options.
The box is shown modally, and the method will block until the user dismisses it.
@param options the options to use when creating the dialog.
@returns the index of the button that was clicked.
@see MessageBoxOptions
*/
static int JUCE_CALLTYPE show (const MessageBoxOptions& options);
#endif #endif
/** Shows a dialog box using the specified options.
The box will be displayed and placed into a modal state, but this method will return
immediately, and the callback will be invoked later when the user dismisses the box.
@param options the options to use when creating the dialog.
@param callback if this is non-null, the callback will receive a call to its
modalStateFinished() when the box is dismissed with the index of the
button that was clicked as its argument.
The callback object will be owned and deleted by the system, so make sure
that it works safely and doesn't keep any references to objects that might
be deleted before it gets called.
@see MessageBoxOptions
*/
static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback);
/** Shows a dialog box using the specified options.
The box will be displayed and placed into a modal state, but this method will return
immediately, and the callback will be invoked later when the user dismisses the box.
@param options the options to use when creating the dialog.
@param callback if this is non-null, the callback will be called when the box is
dismissed with the index of the button that was clicked as its argument.
@see MessageBoxOptions
*/
static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback);
/** Shows a dialog box that just has a message and a single button to get rid of it. /** Shows a dialog box that just has a message and a single button to get rid of it.
The box will be displayed and placed into a modal state, but this method will The box will be displayed and placed into a modal state, but this method will
@@ -272,7 +300,7 @@ public:
safely and doesn't keep any references to objects that might be deleted safely and doesn't keep any references to objects that might be deleted
before it gets called. before it gets called.
*/ */
static void JUCE_CALLTYPE showMessageBoxAsync (AlertIconType iconType,
static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
const String& buttonText = String(), const String& buttonText = String(),
@@ -314,20 +342,20 @@ public:
is not null, the method always returns false, and the user's choice is delivered is not null, the method always returns false, and the user's choice is delivered
later by the callback. later by the callback.
*/ */
static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType,
static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
const String& button1Text = String(), const String& button1Text = String(),
const String& button2Text = String(), const String& button2Text = String(),
Component* associatedComponent = nullptr, Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr); ModalComponentManager::Callback* callback = nullptr);
#else
#else
const String& button1Text, const String& button1Text,
const String& button2Text, const String& button2Text,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback); ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with three buttons. /** Shows a dialog box with three buttons.
@@ -368,24 +396,27 @@ public:
- 1 if the first button was pressed (normally used for 'yes') - 1 if the first button was pressed (normally used for 'yes')
- 2 if the middle button was pressed (normally used for 'no') - 2 if the middle button was pressed (normally used for 'no')
*/ */
static int JUCE_CALLTYPE showYesNoCancelBox (AlertIconType iconType,
static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
const String& button1Text = String(), const String& button1Text = String(),
const String& button2Text = String(), const String& button2Text = String(),
const String& button3Text = String(), const String& button3Text = String(),
Component* associatedComponent = nullptr, Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr); ModalComponentManager::Callback* callback = nullptr);
#else
#else
const String& button1Text, const String& button1Text,
const String& button2Text, const String& button2Text,
const String& button3Text, const String& button3Text,
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback); ModalComponentManager::Callback* callback);
#endif
#endif
//============================================================================== //==============================================================================
#if JUCE_MODAL_LOOPS_PERMITTED
// This has been deprecated, use the NativeMessageBox methods instead for more options.
/** Shows an operating-system native dialog box. /** Shows an operating-system native dialog box.
@param title the title to use at the top @param title the title to use at the top
@@ -394,10 +425,9 @@ public:
it'll show a box with just an ok button it'll show a box with just an ok button
@returns true if the ok button was pressed, false if they pressed cancel. @returns true if the ok button was pressed, false if they pressed cancel.
*/ */
#if JUCE_MODAL_LOOPS_PERMITTED
static bool JUCE_CALLTYPE showNativeDialogBox (const String& title,
const String& bodyText,
bool isOkCancel);
JUCE_DEPRECATED (static bool JUCE_CALLTYPE showNativeDialogBox (const String& title,
const String& bodyText,
bool isOkCancel));
#endif #endif
@@ -428,7 +458,7 @@ public:
const String& button1, const String& button1,
const String& button2, const String& button2,
const String& button3, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, int numButtons,
Component* associatedComponent) = 0; Component* associatedComponent) = 0;
@@ -444,6 +474,14 @@ public:
virtual Font getAlertWindowFont() = 0; virtual Font getAlertWindowFont() = 0;
}; };
//==============================================================================
using AlertIconType = MessageBoxIconType;
static constexpr auto NoIcon = MessageBoxIconType::NoIcon;
static constexpr auto QuestionIcon = MessageBoxIconType::QuestionIcon;
static constexpr auto WarningIcon = MessageBoxIconType::WarningIcon;
static constexpr auto InfoIcon = MessageBoxIconType::InfoIcon;
protected: protected:
//============================================================================== //==============================================================================
/** @internal */ /** @internal */
@@ -470,7 +508,7 @@ private:
String text; String text;
TextLayout textLayout; TextLayout textLayout;
Label accessibleMessageLabel; Label accessibleMessageLabel;
AlertIconType alertIconType;
MessageBoxIconType alertIconType;
ComponentBoundsConstrainer constrainer; ComponentBoundsConstrainer constrainer;
ComponentDragger dragger; ComponentDragger dragger;
Rectangle<int> textArea; Rectangle<int> textArea;


+ 141
- 0
modules/juce_gui_basics/windows/juce_MessageBoxOptions.h View File

@@ -0,0 +1,141 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
/** The type of icon to show in the dialog box. */
enum class MessageBoxIconType
{
NoIcon, /**< No icon will be shown on the dialog box. */
QuestionIcon, /**< A question-mark icon, for dialog boxes that need the
user to answer a question. */
WarningIcon, /**< An exclamation mark to indicate that the dialog is a
warning about something and shouldn't be ignored. */
InfoIcon /**< An icon that indicates that the dialog box is just
giving the user some information, which doesn't require
a response from them. */
};
//==============================================================================
/** Class used to create a set of options to pass to the AlertWindow and NativeMessageBox
methods for showing dialog boxes.
You can chain together a series of calls to this class's methods to create
a set of whatever options you want to specify.
E.g. @code
AlertWindow::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("A Title")
.withMessage ("A message.")
.withButton ("OK")
.withButton ("Cancel")
.withAssociatedComponent (myComp),
myCallback);
@endcode
*/
class JUCE_API MessageBoxOptions
{
public:
MessageBoxOptions() = default;
MessageBoxOptions (const MessageBoxOptions&) = default;
MessageBoxOptions& operator= (const MessageBoxOptions&) = default;
//==============================================================================
/** Sets the type of icon that should be used for the dialog box. */
MessageBoxOptions withIconType (MessageBoxIconType type) const { return with (*this, &MessageBoxOptions::iconType, type); }
/** Sets the title of the dialog box. */
MessageBoxOptions withTitle (const String& boxTitle) const { return with (*this, &MessageBoxOptions::title, boxTitle); }
/** Sets the message that should be displayed in the dialog box. */
MessageBoxOptions withMessage (const String& boxMessage) const { return with (*this, &MessageBoxOptions::message, boxMessage); }
/** If the string passed in is not empty, this will add a button to the
dialog box with the specified text.
Generally up to 3 buttons are supported for dialog boxes, so adding any more
than this may have no effect.
*/
MessageBoxOptions withButton (const String& text) const { auto copy = *this; copy.buttons.add (text); return copy; }
/** The component that the dialog box should be associated with. */
MessageBoxOptions withAssociatedComponent (Component* component) const { return with (*this, &MessageBoxOptions::associatedComponent, component); }
//==============================================================================
/** Returns the icon type of the dialog box.
@see withIconType
*/
MessageBoxIconType getIconType() const noexcept { return iconType; }
/** Returns the title of the dialog box.
@see withTitle
*/
String getTitle() const { return title; }
/** Returns the message of the dialog box.
@see withMessage
*/
String getMessage() const { return message; }
/** Returns the number of buttons that have been added to the dialog box.
@see withButtonText
*/
int getNumButtons() const noexcept { return buttons.size(); }
/** Returns the text that has been set for one of the buttons of the dialog box.
@see withButtonText, getNumButtons
*/
String getButtonText (int buttonIndex) const { return buttons[buttonIndex]; }
/** Returns the component that the dialog box is associated with.
@see withAssociatedComponent
*/
Component* getAssociatedComponent() const noexcept { return associatedComponent; }
private:
//==============================================================================
template <typename Member, typename Item>
static MessageBoxOptions with (MessageBoxOptions options, Member&& member, Item&& item)
{
options.*member = std::forward<Item> (item);
return options;
}
//==============================================================================
MessageBoxIconType iconType = MessageBoxIconType::InfoIcon;
String title, message;
StringArray buttons;
WeakReference<Component> associatedComponent;
};
} // namespace juce

+ 87
- 43
modules/juce_gui_basics/windows/juce_NativeMessageBox.h View File

@@ -35,33 +35,77 @@ namespace juce
class NativeMessageBox class NativeMessageBox
{ {
public: public:
#if JUCE_MODAL_LOOPS_PERMITTED
/** Shows a dialog box that just has a message and a single 'ok' button to close it. /** Shows a dialog box that just has a message and a single 'ok' button to close it.
The box is shown modally, and the method will block until the user has clicked its The box is shown modally, and the method will block until the user has clicked its
button (or pressed the escape or return keys). button (or pressed the escape or return keys).
@param iconType the type of icon to show
@param title the headline to show at the top of the box
@param message a longer, more descriptive message to show underneath the title
@param iconType the type of icon to show.
@param title the headline to show at the top of the box.
@param message a longer, more descriptive message to show underneath the title.
@param associatedComponent if this is non-null, it specifies the component that the @param associatedComponent if this is non-null, it specifies the component that the
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
*/ */
#if JUCE_MODAL_LOOPS_PERMITTED
static void JUCE_CALLTYPE showMessageBox (AlertWindow::AlertIconType iconType,
static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
Component* associatedComponent = nullptr); Component* associatedComponent = nullptr);
/** Shows a dialog box using the specified options.
The box is shown modally, and the method will block until the user dismisses it.
@param options the options to use when creating the dialog.
@returns the index of the button that was clicked.
@see MessageBoxOptions
*/
static int JUCE_CALLTYPE show (const MessageBoxOptions& options);
#endif #endif
/** Shows a dialog box using the specified options.
The box will be displayed and placed into a modal state, but this method will return
immediately, and the callback will be invoked later when the user dismisses the box.
@param options the options to use when creating the dialog.
@param callback if this is non-null, the callback will receive a call to its
modalStateFinished() when the box is dismissed with the index of the
button that was clicked as its argument.
The callback object will be owned and deleted by the system, so make sure
that it works safely and doesn't keep any references to objects that might
be deleted before it gets called.
@see MessageBoxOptions
*/
static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
ModalComponentManager::Callback* callback);
/** Shows a dialog box using the specified options.
The box will be displayed and placed into a modal state, but this method will return
immediately, and the callback will be invoked later when the user dismisses the box.
@param options the options to use when creating the dialog.
@param callback if this is non-null, the callback will be called when the box is
dismissed with the index of the button that was clicked as its argument.
@see MessageBoxOptions
*/
static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
std::function<void (int)> callback);
/** Shows a dialog box that just has a message and a single 'ok' button to close it. /** Shows a dialog box that just has a message and a single 'ok' button to close it.
The box will be displayed and placed into a modal state, but this method will return The box will be displayed and placed into a modal state, but this method will return
immediately, and the callback will be invoked later when the user dismisses the box. immediately, and the callback will be invoked later when the user dismisses the box.
@param iconType the type of icon to show
@param title the headline to show at the top of the box
@param message a longer, more descriptive message to show underneath the title
@param iconType the type of icon to show.
@param title the headline to show at the top of the box.
@param message a longer, more descriptive message to show underneath the title.
@param associatedComponent if this is non-null, it specifies the component that the @param associatedComponent if this is non-null, it specifies the component that the
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
@@ -74,26 +118,26 @@ public:
@see ModalCallbackFunction @see ModalCallbackFunction
*/ */
static void JUCE_CALLTYPE showMessageBoxAsync (AlertWindow::AlertIconType iconType,
const String& title,
const String& message,
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
const String& title,
const String& message,
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
/** Shows a dialog box with two buttons. /** Shows a dialog box with two buttons.
Ideal for ok/cancel or yes/no choices. The return key can also be used Ideal for ok/cancel or yes/no choices. The return key can also be used
to trigger the first button, and the escape key for the second button. to trigger the first button, and the escape key for the second button.
If the callback parameter is null, the box is shown modally, and the method will
block until the user has clicked the button (or pressed the escape or return keys).
If the callback parameter is non-null, the box will be displayed and placed into a
modal state, but this method will return immediately, and the callback will be invoked
If the callback parameter is null and modal loops are enabled, the box is shown modally,
and the method will block until the user has clicked the button (or pressed the escape or
return keys). If the callback parameter is non-null, the box will be displayed and placed
into a modal state, but this method will return immediately, and the callback will be invoked
later when the user dismisses the box. later when the user dismisses the box.
@param iconType the type of icon to show
@param title the headline to show at the top of the box
@param message a longer, more descriptive message to show underneath the title
@param iconType the type of icon to show.
@param title the headline to show at the top of the box.
@param message a longer, more descriptive message to show underneath the title.
@param associatedComponent if this is non-null, it specifies the component that the @param associatedComponent if this is non-null, it specifies the component that the
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
@@ -111,16 +155,16 @@ public:
@see ModalCallbackFunction @see ModalCallbackFunction
*/ */
static bool JUCE_CALLTYPE showOkCancelBox (AlertWindow::AlertIconType iconType,
static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
Component* associatedComponent = nullptr, Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr); ModalComponentManager::Callback* callback = nullptr);
#else
#else
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback); ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with three buttons. /** Shows a dialog box with three buttons.
@@ -128,15 +172,15 @@ public:
The escape key can be used to trigger the third button. The escape key can be used to trigger the third button.
If the callback parameter is null, the box is shown modally, and the method will
block until the user has clicked the button (or pressed the escape or return keys).
If the callback parameter is non-null, the box will be displayed and placed into a
modal state, but this method will return immediately, and the callback will be invoked
If the callback parameter is null and modal loops are enabled, the box is shown modally,
and the method will block until the user has clicked the button (or pressed the escape or
return keys). If the callback parameter is non-null, the box will be displayed and placed
into a modal state, but this method will return immediately, and the callback will be invoked
later when the user dismisses the box. later when the user dismisses the box.
@param iconType the type of icon to show
@param title the headline to show at the top of the box
@param message a longer, more descriptive message to show underneath the title
@param iconType the type of icon to show.
@param title the headline to show at the top of the box.
@param message a longer, more descriptive message to show underneath the title.
@param associatedComponent if this is non-null, it specifies the component that the @param associatedComponent if this is non-null, it specifies the component that the
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
@@ -157,16 +201,16 @@ public:
@see ModalCallbackFunction @see ModalCallbackFunction
*/ */
static int JUCE_CALLTYPE showYesNoCancelBox (AlertWindow::AlertIconType iconType,
static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
Component* associatedComponent = nullptr, Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr); ModalComponentManager::Callback* callback = nullptr);
#else
#else
Component* associatedComponent, Component* associatedComponent,
ModalComponentManager::Callback* callback); ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with two buttons. /** Shows a dialog box with two buttons.
@@ -174,15 +218,15 @@ public:
The escape key can be used to trigger the no button. The escape key can be used to trigger the no button.
If the callback parameter is null, the box is shown modally, and the method will
block until the user has clicked the button (or pressed the escape or return keys).
If the callback parameter is non-null, the box will be displayed and placed into a
modal state, but this method will return immediately, and the callback will be invoked
If the callback parameter is null and modal loops are enabled, the box is shown modally,
and the method will block until the user has clicked the button (or pressed the escape or
return keys). If the callback parameter is non-null, the box will be displayed and placed
into a modal state, but this method will return immediately, and the callback will be invoked
later when the user dismisses the box. later when the user dismisses the box.
@param iconType the type of icon to show
@param title the headline to show at the top of the box
@param message a longer, more descriptive message to show underneath the title
@param iconType the type of icon to show.
@param title the headline to show at the top of the box.
@param message a longer, more descriptive message to show underneath the title.
@param associatedComponent if this is non-null, it specifies the component that the @param associatedComponent if this is non-null, it specifies the component that the
alert window should be associated with. Depending on the look alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window. and feel, this might be used for positioning of the alert window.
@@ -202,7 +246,7 @@ public:
@see ModalCallbackFunction @see ModalCallbackFunction
*/ */
static int JUCE_CALLTYPE showYesNoBox (AlertWindow::AlertIconType iconType,
static int JUCE_CALLTYPE showYesNoBox (MessageBoxIconType iconType,
const String& title, const String& title,
const String& message, const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED


+ 1
- 1
modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp View File

@@ -41,7 +41,7 @@ ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title,
.createAlertWindow (title, {}, .createAlertWindow (title, {},
cancelButtonText.isEmpty() ? TRANS("Cancel") cancelButtonText.isEmpty() ? TRANS("Cancel")
: cancelButtonText, : cancelButtonText,
{}, {}, AlertWindow::NoIcon, hasCancelButton ? 1 : 0,
{}, {}, MessageBoxIconType::NoIcon, hasCancelButton ? 1 : 0,
componentToCentreAround)); componentToCentreAround));
// if there are no buttons, we won't allow the user to interrupt the thread. // if there are no buttons, we won't allow the user to interrupt the thread.


+ 4
- 4
modules/juce_gui_extra/documents/juce_FileBasedDocument.cpp View File

@@ -339,7 +339,7 @@ private:
auto result = Result::fail (TRANS ("The file doesn't exist")); auto result = Result::fail (TRANS ("The file doesn't exist"));
if (showMessageOnFailure) if (showMessageOnFailure)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("Failed to open file..."), TRANS ("Failed to open file..."),
TRANS ("There was an error while trying to load the file: FLNM") TRANS ("There was an error while trying to load the file: FLNM")
.replace ("FLNM", "\n" + newFile.getFullPathName()) .replace ("FLNM", "\n" + newFile.getFullPathName())
@@ -448,7 +448,7 @@ private:
callback (parent, alertResult); callback (parent, alertResult);
}); });
return AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
return AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon,
TRANS ("Closing document..."), TRANS ("Closing document..."),
TRANS ("Do you want to save the changes to \"DCNM\"?") TRANS ("Do you want to save the changes to \"DCNM\"?")
.replace ("DCNM", document.getDocumentTitle()), .replace ("DCNM", document.getDocumentTitle()),
@@ -510,7 +510,7 @@ private:
MouseCursor::hideWaitCursor(); MouseCursor::hideWaitCursor();
if (showMessageOnFailure) if (showMessageOnFailure)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("Error writing to file..."), TRANS ("Error writing to file..."),
TRANS ("An error occurred while trying to save \"DCNM\" to the file: FLNM") TRANS ("An error occurred while trying to save \"DCNM\" to the file: FLNM")
.replace ("DCNM", parent->document.getDocumentTitle()) .replace ("DCNM", parent->document.getDocumentTitle())
@@ -682,7 +682,7 @@ private:
callback (parent, r == 1); callback (parent, r == 1);
}); });
return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
return AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS ("File already exists"), TRANS ("File already exists"),
TRANS ("There's already a file called: FLNM") TRANS ("There's already a file called: FLNM")
.replace ("FLNM", newFile.getFullPathName()) .replace ("FLNM", newFile.getFullPathName())


+ 3
- 3
modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.cpp View File

@@ -98,7 +98,7 @@ public:
KeyEntryWindow (KeyMappingEditorComponent& kec) KeyEntryWindow (KeyMappingEditorComponent& kec)
: AlertWindow (TRANS("New key-mapping"), : AlertWindow (TRANS("New key-mapping"),
TRANS("Please press a key combination now..."), TRANS("Please press a key combination now..."),
AlertWindow::NoIcon),
MessageBoxIconType::NoIcon),
owner (kec) owner (kec)
{ {
addButton (TRANS("OK"), 1); addButton (TRANS("OK"), 1);
@@ -165,7 +165,7 @@ public:
} }
else else
{ {
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS("Change key-mapping"), TRANS("Change key-mapping"),
TRANS("This key is already assigned to the command \"CMDN\"") TRANS("This key is already assigned to the command \"CMDN\"")
.replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand)) .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand))
@@ -403,7 +403,7 @@ KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappin
resetButton.onClick = [this] resetButton.onClick = [this]
{ {
AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon,
TRANS("Reset to defaults"), TRANS("Reset to defaults"),
TRANS("Are you sure you want to reset all the key-mappings to their default state?"), TRANS("Are you sure you want to reset all the key-mappings to their default state?"),
TRANS("Reset"), TRANS("Reset"),


+ 2
- 2
modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.cpp View File

@@ -100,13 +100,13 @@ struct OnlineUnlockForm::OverlayComp : public Component,
if (result.errorMessage.isNotEmpty()) if (result.errorMessage.isNotEmpty())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Registration Failed"), TRANS("Registration Failed"),
result.errorMessage); result.errorMessage);
} }
else if (result.informativeMessage.isNotEmpty()) else if (result.informativeMessage.isNotEmpty())
{ {
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
TRANS("Registration Complete!"), TRANS("Registration Complete!"),
result.informativeMessage); result.informativeMessage);
} }


Loading…
Cancel
Save