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();
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
thumbnailComp.setCurrentURL (u);
}


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

@@ -529,10 +529,13 @@ private:
}
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();
if (! success && error.isNotEmpty())
{
NativeMessageBox::showMessageBoxAsync (AlertWindow::WarningIcon,
"Sharing Error",
error);
}
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Sharing Error")
.withMessage (error),
nullptr);
});
#endif


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

@@ -524,7 +524,7 @@ private:
void handleInvalidLegacyModeParameters() const
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Invalid legacy mode channel layout",
"Cannot set legacy mode start/end channel:\n"
"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);
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);
}


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

@@ -252,7 +252,7 @@ private:
}
else
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Camera open failed",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Camera open failed",
"Camera open failed, reason: " + error);
}
@@ -365,7 +365,7 @@ private:
void errorOccurred (const String& error)
{
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Camera Device Error",
"An error has occurred: " + error + " Camera will be closed.");
@@ -378,7 +378,7 @@ private:
void sharingFinished (bool success, bool isCapture)
{
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
isCapture ? "Image sharing result" : "Video sharing result",
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..
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..
delete this;
@@ -177,12 +172,13 @@ public:
[] (bool 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
{
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 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;
@@ -259,11 +262,11 @@ private:
{
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",
"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)
{
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.",
{}, {}, {},
ModalCallbackFunction::create (AlertBoxResultChosen{}));
@@ -291,7 +294,7 @@ private:
{
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.",
AlertWindow::QuestionIcon);
MessageBoxIconType::QuestionIcon);
asyncAlertWindow->addTextEditor ("text", "enter some text here", "text field:");
asyncAlertWindow->addComboBox ("option", { "option 1", "option 2", "option 3", "option 4" }, "some options");
@@ -326,9 +329,12 @@ private:
chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName()
: 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)
@@ -349,9 +355,12 @@ private:
chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName()
: 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);
}
@@ -401,9 +410,12 @@ private:
}
#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)
@@ -420,9 +432,12 @@ private:
auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName()
: 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 + ")");
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)
@@ -454,9 +473,12 @@ private:
{
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")
: ("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
{
++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!");
refresh();
}


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

@@ -134,7 +134,7 @@ private:
}
else
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Couldn't load the file!",
result.getErrorMessage());
}
@@ -354,7 +354,7 @@ public:
{
if (! granted)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Permissions warning",
"External storage access permission not granted, some files"
" may be inaccessible.");
@@ -503,7 +503,7 @@ private:
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 ("No", 0, KeyPress (KeyPress::escapeKey));
@@ -559,7 +559,7 @@ private:
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 ("Cancel", 0, KeyPress (KeyPress::escapeKey));
@@ -596,7 +596,7 @@ private:
}
else
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Couldn't load the file!",
result.getErrorMessage());
}
@@ -677,7 +677,7 @@ private:
void errorOccurred (const String& errorMessage)
{
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"An error has occurred",
errorMessage + ", video will be unloaded.");


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

@@ -156,7 +156,7 @@ private:
voiceProduct.purchasePrice = "In-App purchases unavailable";
}
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"In-app purchase is unavailable!",
"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 "
@@ -178,7 +178,7 @@ private:
}
}
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Your credit card will be charged!",
"You are running the sample code for JUCE In-App purchases. "
"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)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Connection error",
messageText,
"OK");
@@ -273,7 +273,7 @@ private:
void showConnectionErrorMessage (const String& messageText)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Connection error",
messageText,
"OK");
@@ -403,7 +403,7 @@ private:
//==============================================================================
void handleConnectError (int failedPort)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"OSC Connection error",
"Error: could not connect to port " + String (failedPort),
"OK");
@@ -412,7 +412,7 @@ private:
//==============================================================================
void handleDisconnectError()
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Unknown error",
"An unknown error occurred while trying to disconnect from UDP port.",
"OK");
@@ -421,7 +421,7 @@ private:
//==============================================================================
void handleInvalidPortNumberEntered()
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Invalid port number",
"Error: you have entered an invalid UDP port number.",
"OK");


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

@@ -194,7 +194,11 @@ public:
if (token.isEmpty())
showRemoteInstructions();
else
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Device token", token);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Device token")
.withMessage (token),
nullptr);
};
#if JUCE_ANDROID
@@ -308,11 +312,11 @@ private:
String requiredFields = "all required fields";
#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;
}
@@ -559,11 +563,13 @@ private:
{
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,
@@ -573,24 +579,28 @@ private:
{
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);
}
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
@@ -600,7 +610,11 @@ private:
for (auto& n : notifs)
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
@@ -610,37 +624,49 @@ private:
for (auto& n : notifs)
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
{
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
"Device token refreshed",
token);
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::InfoIcon)
.withTitle ("Device token refreshed")
.withMessage (token),
nullptr);
}
#if JUCE_ANDROID
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
{
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
{
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()
@@ -1191,12 +1217,14 @@ private:
static void showRemoteInstructions()
{
#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
}


+ 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)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Couldn't create plugin"),
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)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Errors in Creating Project!"),
TRANS("The following files couldn't be written:")
+ "\n\n"
@@ -244,7 +244,7 @@ static void prepareDirectory (const File& targetFolder, Callback&& callback)
}
else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
{
AlertWindow::showOkCancelBox (AlertWindow::InfoIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::InfoIcon,
TRANS("New JUCE Project"),
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?")


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

@@ -122,7 +122,7 @@ private:
if (postStrings.size() != preStrings.size())
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Error"),
TRANS("The pre- and post-translation text doesn't match!\n\n"
"Perhaps it got mangled by the translator?"));
@@ -138,7 +138,7 @@ private:
if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject())
setPreTranslationText (TranslationHelpers::getPreTranslationText (*project));
else
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Translation Tool",
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool",
"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."
" Please compile the Demo Runner project in the JUCE examples directory.",
"OK", {}, {},
AlertWindow::WarningIcon, 1,
MessageBoxIconType::WarningIcon, 1,
mainWindowList.getFrontmostWindow (false)));
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int)
{
@@ -847,7 +847,7 @@ void ProjucerApplication::launchDemoRunner()
"Couldn't find a compiled version of the Demo Runner."
" Do you want to open the project?",
"Open project", "Cancel", {},
AlertWindow::QuestionIcon, 2,
MessageBoxIconType::QuestionIcon, 2,
mainWindowList.getFrontmostWindow (false)));
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal)
{
@@ -1102,7 +1102,7 @@ void ProjucerApplication::createNewProjectFromClipboard()
{
if (errorString.isNotEmpty())
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", errorString);
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Error", errorString);
tempFile.deleteFile();
}
};


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

@@ -56,7 +56,7 @@ void LatestVersionCheckerAndUpdater::run()
if (info == nullptr)
{
if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Update Server Communication Error",
"Failed to communicate with the JUCE update server.\n"
"Please try again in a few minutes.\n\n"
@@ -68,7 +68,7 @@ void LatestVersionCheckerAndUpdater::run()
if (! info->isNewerVersionThanCurrent())
{
if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"No New Version Available",
"Your JUCE version is up to date.");
return;
@@ -109,7 +109,7 @@ void LatestVersionCheckerAndUpdater::run()
}
if (! backgroundCheck)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Failed to find any new downloads",
"Please try again in a few minutes.");
}
@@ -275,13 +275,13 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version
{
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.");
return;
}
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Overwrite Existing JUCE Folder?",
"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"
@@ -295,7 +295,7 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version
if (targetFolder.exists())
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Existing File Or Directory",
"Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?",
{},
@@ -388,7 +388,7 @@ private:
result = install (zipData);
if (result.failed())
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Installation Failed",
result.getErrorMessage()); });
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())
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.",
generatorResult.getErrorMessage());
@@ -464,7 +464,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba
if (! generator->createMainCpp())
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.",
"Failed to create Main.cpp.");
@@ -481,7 +481,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba
if (! openedSuccessfully)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"PIP Error.",
"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;
}
AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon,
TRANS("Closing document..."),
TRANS("Do you want to save the changes to \"")
+ 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"),
TRANS ("Please enter a name for the new class"),
AlertWindow::NoIcon,
MessageBoxIconType::NoIcon,
nullptr);
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]);
if (failed.size() > 0)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Reloading resources"),
TRANS("The following resources couldn't be reloaded from their original files:\n\n")
+ 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()))
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Adding Resource"),
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())
{
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Add Module", "This wasn't a valid module folder!");
return;
}
if (isModuleEnabled (m.getID()))
{
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
"Add Module", "The project already contains this module!");
return;
}


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

@@ -90,7 +90,7 @@ public:
safeThis->project.getUndoManagerFor (parent));
};
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Delete Exporter",
"Are you sure you want to delete this export target?",
"",
@@ -244,7 +244,7 @@ public:
void deleteItem() override
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
"Delete 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)
fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files...";
AlertWindow::showYesNoCancelBox (AlertWindow::NoIcon,
AlertWindow::showYesNoCancelBox (MessageBoxIconType::NoIcon,
"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"
+ fileList,
@@ -521,7 +521,7 @@ public:
{
if (newName != File::createLegalFileName (newName))
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename",
"That filename contained some illegal characters!");
triggerAsyncRename (item);
@@ -538,7 +538,7 @@ public:
if (correspondingItem.isValid())
{
AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::NoIcon,
"File Rename",
"Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?",
{},
@@ -552,7 +552,7 @@ public:
if (! parent->item.renameFile (newFile))
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename",
"Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!");
return;
@@ -560,7 +560,7 @@ public:
if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension())))
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename",
"Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!");
}
@@ -571,7 +571,7 @@ public:
if (! item.renameFile (newFile))
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"File Rename",
"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);
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Adding Missing Dependencies",
"Couldn't locate some of these modules - you'll need to find their "
"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)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS("Save failed!"),
TRANS("Couldn't save the file:")
+ "\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)
std::cout << "WARNING! The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project." << std::endl;
else
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS (oldExporters[key]),
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"
"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(),
alertWindowText, "Update", "Cancel", nullptr, nullptr))
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"),
TRANS ("Please enter the name for the new class"),
AlertWindow::NoIcon, nullptr);
MessageBoxIconType::NoIcon, nullptr);
asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false);
asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey));
@@ -235,7 +235,7 @@ public:
//==============================================================================
void NewFileWizard::Type::showFailedToWriteMessage (const File& file)
{
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
"Failed to Create File!",
"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,
const String& title, const String& text)
: 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)
{
FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
@@ -467,7 +467,7 @@ private:
if (isStupidPath (f))
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS("Plugin Scanning"),
TRANS("If you choose to scan folders that contain non-plugin files, "
"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
if (shortNames.size() > 0)
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
TRANS("Scan complete"),
TRANS("Note that the following files appeared to be plugin files, but failed to load correctly")
+ ":\n\n"


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

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


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

@@ -289,25 +289,4 @@ int ModalComponentManager::runEventLoopForCurrentComponent()
}
#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

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

@@ -163,14 +163,26 @@ class JUCE_API ModalCallbackFunction
{
public:
/** 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.
@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


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

@@ -194,7 +194,7 @@ void FileChooserDialogBox::okButtonPressed()
&& content->chooserComponent.isSaveMode()
&& content->chooserComponent.getSelectedFile(0).exists())
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS("File already exists"),
TRANS("There's already a file called: FLNM")
.replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
@@ -229,7 +229,7 @@ void FileChooserDialogBox::createNewFolder()
{
auto* aw = new AlertWindow (TRANS("New Folder"),
TRANS("Please enter the name for the folder"),
AlertWindow::NoIcon, this);
MessageBoxIconType::NoIcon, this);
aw->addTextEditor ("Folder Name", String(), String(), false);
aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey));
@@ -251,7 +251,7 @@ void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialo
auto parent = content->chooserComponent.getRoot();
if (! parent.getChildFile (name).createDirectory())
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("New 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 <vfw.h>
#include <commdlg.h>
#include <commctrl.h>
#if ! JUCE_MINGW
#include <UIAutomation.h>
@@ -82,6 +83,7 @@
#elif ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "imm32.lib")
#pragma comment(lib, "comctl32.lib")
#if JUCE_OPENGL
#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 "widgets/juce_TreeView.h"
#include "windows/juce_TopLevelWindow.h"
#include "windows/juce_MessageBoxOptions.h"
#include "windows/juce_AlertWindow.h"
#include "windows/juce_CallOutBox.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,
const String& button1, const String& button2, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* 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,
iconSize, iconSize);
if (alert.getAlertType() != AlertWindow::NoIcon)
if (alert.getAlertType() != MessageBoxIconType::NoIcon)
{
Path icon;
uint32 colour;
char character;
if (alert.getAlertType() == AlertWindow::WarningIcon)
if (alert.getAlertType() == MessageBoxIconType::WarningIcon)
{
colour = 0x55ff5555;
character = '!';
@@ -476,8 +476,8 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert,
}
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());
}


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

@@ -67,7 +67,7 @@ public:
const String& button1,
const String& button2,
const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) 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,
const String& button1, const String& button2, const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent)
{
auto boundsOffset = 50;
@@ -429,13 +429,13 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert,
Rectangle<int> iconRect (iconSize / -10, iconSize / -10,
iconSize, iconSize);
if (alert.getAlertType() != AlertWindow::NoIcon)
if (alert.getAlertType() != MessageBoxIconType::NoIcon)
{
Path icon;
char character;
uint32 colour;
if (alert.getAlertType() == AlertWindow::WarningIcon)
if (alert.getAlertType() == MessageBoxIconType::WarningIcon)
{
character = '!';
@@ -449,7 +449,7 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert,
else
{
colour = Colour (0xff00b0b9).withAlpha (0.4f).getARGB();
character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?';
character = alert.getAlertType() == MessageBoxIconType::InfoIcon ? 'i' : '?';
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& button2,
const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons, Component* associatedComponent) 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
{
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)
@@ -1257,46 +1257,44 @@ private:
return AndroidInterfaceImplementer::invoke (proxy, method, args);
}
std::unique_ptr<ModalComponentManager::Callback> callback;
std::shared_ptr<ModalComponentManager::Callback> callback;
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();
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.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,
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,
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));
@@ -1315,47 +1313,76 @@ static void createAndroidDialog (const String& title, const String& message,
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,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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;
}
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (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"))
.withButton (TRANS("Cancel")),
AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel));
createAndroidDialog (title, message, callback, "Yes", "No", "Cancel");
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;
}
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;


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

@@ -437,19 +437,18 @@ void LookAndFeel::playAlertSound()
class iOSMessageBox
{
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)
{
UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title)
message: juceStringToNS (message)
UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (opts.getTitle())
message: juceStringToNS (opts.getMessage())
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
animated: YES
@@ -469,105 +468,146 @@ public:
JUCE_AUTORELEASEPOOL
{
while (! resultReceived)
while (result < 0)
[[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
}
return result;
}
void buttonClicked (const int buttonIndex) noexcept
void buttonClicked (int buttonIndex) noexcept
{
result = buttonIndex;
resultReceived = true;
if (callback != nullptr)
callback->modalStateFinished (result);
callback->modalStateFinished (buttonIndex);
if (isAsync)
delete this;
delete this;
}
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
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)
};
//==============================================================================
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType /*iconType*/,
const String& title, const String& message,
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/,
const String& title, const String& message,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message,
Component*)
Component* /*associatedComponent*/)
{
AlertWindow::showMessageBox (iconType, title, message);
}
int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
{
return showDialog (options, nullptr, Async::no);
}
#endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
@@ -671,7 +741,7 @@ void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIcon
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,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
@@ -679,7 +749,7 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType
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,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
@@ -688,15 +758,27 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy
associatedComponent, callback);
}
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType,
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
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);
}
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&)
{


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

@@ -35,47 +35,29 @@ void LookAndFeel::playAlertSound()
class OSXMessageBox : private AsyncUpdater
{
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
{
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;
}
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
{
auto result = getResult();
@@ -86,73 +68,147 @@ private:
delete this;
}
static void addButton (NSAlert* alert, const String& button)
{
if (! button.isEmpty())
[alert addButtonWithTitle: juceStringToNS (button)];
}
NSInteger getRawResult() const
{
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];
}
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message,
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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,
Component* /*associatedComponent*/,
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)


+ 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:
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
{
const int result = getResult();
const auto result = getResult();
if (callback != nullptr)
callback->modalStateFinished (result);
@@ -4442,97 +4456,303 @@ public:
delete this;
}
private:
UINT flags;
HWND owner;
String title, message;
Component::SafePointer<Component> associatedComponent;
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
// 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
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
const String& title, const String& message,
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
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
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,
Component* associatedComponent,
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,
Component* associatedComponent,
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,
Component* associatedComponent,
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,
const String& message,
AlertIconType iconType,
MessageBoxIconType iconType,
Component* comp)
: TopLevelWindow (title, true),
alertIconType (iconType),
@@ -561,20 +561,21 @@ int AlertWindow::getDesktopWindowStyleFlags() const
return getLookAndFeel().getAlertBoxWindowFlags();
}
enum class Async { no, yes };
//==============================================================================
class AlertWindowInfo
{
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
{
MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
@@ -582,88 +583,153 @@ public:
}
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()
{
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!
alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
#if JUCE_MODAL_LOOPS_PERMITTED
if (modal)
{
if (async == Async::no)
returnValue = alertBox->runModalLoop();
}
else
#endif
{
ignoreUnused (modal);
ignoreUnused (async);
alertBox->enterModalState (true, callback, true);
alertBox->enterModalState (true, callback.release(), true);
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
void AlertWindow::showMessageBox (AlertIconType iconType,
void AlertWindow::showMessageBox (MessageBoxIconType iconType,
const String& title,
const String& message,
const String& buttonText,
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())
{
NativeMessageBox::showMessageBox (iconType, title, message, associatedComponent);
NativeMessageBox::showAsync (options, callback);
}
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();
}
}
#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& message,
const String& buttonText,
Component* associatedComponent,
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())
{
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& message,
const String& button1Text,
@@ -672,16 +738,19 @@ bool AlertWindow::showOkCancelBox (AlertIconType iconType,
ModalComponentManager::Callback* callback)
{
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& message,
const String& button1Text,
@@ -691,29 +760,19 @@ int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
ModalComponentManager::Callback* callback)
{
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()
{


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

@@ -44,20 +44,6 @@ namespace juce
class JUCE_API AlertWindow : public TopLevelWindow
{
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.
@@ -71,7 +57,7 @@ public:
*/
AlertWindow (const String& title,
const String& message,
AlertIconType iconType,
MessageBoxIconType iconType,
Component* associatedComponent = nullptr);
/** Destroys the AlertWindow */
@@ -80,7 +66,7 @@ public:
//==============================================================================
/** Returns the type of alert icon that was specified when the window
was created. */
AlertIconType getAlertType() const noexcept { return alertIconType; }
MessageBoxIconType getAlertType() const noexcept { return alertIconType; }
//==============================================================================
/** Changes the dialog box's message.
@@ -226,8 +212,6 @@ public:
bool containsAnyExtraComponents() const;
//==============================================================================
// easy-to-use message box functions:
#if JUCE_MODAL_LOOPS_PERMITTED
/** 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
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& message,
const String& buttonText = String(),
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
/** 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.
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
before it gets called.
*/
static void JUCE_CALLTYPE showMessageBoxAsync (AlertIconType iconType,
static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
const String& title,
const String& message,
const String& buttonText = String(),
@@ -314,20 +342,20 @@ public:
is not null, the method always returns false, and the user's choice is delivered
later by the callback.
*/
static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType,
static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
const String& title,
const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
const String& button1Text = String(),
const String& button2Text = String(),
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
#else
#else
const String& button1Text,
const String& button2Text,
Component* associatedComponent,
ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with three buttons.
@@ -368,24 +396,27 @@ public:
- 1 if the first button was pressed (normally used for 'yes')
- 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& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
const String& button1Text = String(),
const String& button2Text = String(),
const String& button3Text = String(),
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
#else
#else
const String& button1Text,
const String& button2Text,
const String& button3Text,
Component* associatedComponent,
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.
@param title the title to use at the top
@@ -394,10 +425,9 @@ public:
it'll show a box with just an ok button
@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
@@ -428,7 +458,7 @@ public:
const String& button1,
const String& button2,
const String& button3,
AlertWindow::AlertIconType iconType,
MessageBoxIconType iconType,
int numButtons,
Component* associatedComponent) = 0;
@@ -444,6 +474,14 @@ public:
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:
//==============================================================================
/** @internal */
@@ -470,7 +508,7 @@ private:
String text;
TextLayout textLayout;
Label accessibleMessageLabel;
AlertIconType alertIconType;
MessageBoxIconType alertIconType;
ComponentBoundsConstrainer constrainer;
ComponentDragger dragger;
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
{
public:
#if JUCE_MODAL_LOOPS_PERMITTED
/** 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
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
alert window should be associated with. Depending on the look
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& message,
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
/** 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.
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 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
alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window.
@@ -74,26 +118,26 @@ public:
@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.
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.
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.
@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
alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window.
@@ -111,16 +155,16 @@ public:
@see ModalCallbackFunction
*/
static bool JUCE_CALLTYPE showOkCancelBox (AlertWindow::AlertIconType iconType,
static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
const String& title,
const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
#else
#else
Component* associatedComponent,
ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with three buttons.
@@ -128,15 +172,15 @@ public:
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.
@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
alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window.
@@ -157,16 +201,16 @@ public:
@see ModalCallbackFunction
*/
static int JUCE_CALLTYPE showYesNoCancelBox (AlertWindow::AlertIconType iconType,
static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
const String& title,
const String& message,
#if JUCE_MODAL_LOOPS_PERMITTED
#if JUCE_MODAL_LOOPS_PERMITTED
Component* associatedComponent = nullptr,
ModalComponentManager::Callback* callback = nullptr);
#else
#else
Component* associatedComponent,
ModalComponentManager::Callback* callback);
#endif
#endif
/** Shows a dialog box with two buttons.
@@ -174,15 +218,15 @@ public:
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.
@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
alert window should be associated with. Depending on the look
and feel, this might be used for positioning of the alert window.
@@ -202,7 +246,7 @@ public:
@see ModalCallbackFunction
*/
static int JUCE_CALLTYPE showYesNoBox (AlertWindow::AlertIconType iconType,
static int JUCE_CALLTYPE showYesNoBox (MessageBoxIconType iconType,
const String& title,
const String& message,
#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, {},
cancelButtonText.isEmpty() ? TRANS("Cancel")
: cancelButtonText,
{}, {}, AlertWindow::NoIcon, hasCancelButton ? 1 : 0,
{}, {}, MessageBoxIconType::NoIcon, hasCancelButton ? 1 : 0,
componentToCentreAround));
// 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"));
if (showMessageOnFailure)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("Failed to open file..."),
TRANS ("There was an error while trying to load the file: FLNM")
.replace ("FLNM", "\n" + newFile.getFullPathName())
@@ -448,7 +448,7 @@ private:
callback (parent, alertResult);
});
return AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
return AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon,
TRANS ("Closing document..."),
TRANS ("Do you want to save the changes to \"DCNM\"?")
.replace ("DCNM", document.getDocumentTitle()),
@@ -510,7 +510,7 @@ private:
MouseCursor::hideWaitCursor();
if (showMessageOnFailure)
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
TRANS ("Error writing to file..."),
TRANS ("An error occurred while trying to save \"DCNM\" to the file: FLNM")
.replace ("DCNM", parent->document.getDocumentTitle())
@@ -682,7 +682,7 @@ private:
callback (parent, r == 1);
});
return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
return AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
TRANS ("File already exists"),
TRANS ("There's already a file called: FLNM")
.replace ("FLNM", newFile.getFullPathName())


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

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


Loading…
Cancel
Save