- 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 availablev6.1.6
| @@ -612,7 +612,11 @@ private: | |||||
| auto u = fc.getURLResult(); | auto u = fc.getURLResult(); | ||||
| if (! audioFileReader.loadURL (u)) | if (! audioFileReader.loadURL (u)) | ||||
| NativeMessageBox::showOkCancelBox (AlertWindow::WarningIcon, "Error loading file", "Unable to load audio file", nullptr, nullptr); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::WarningIcon) | |||||
| .withTitle ("Error loading file") | |||||
| .withMessage ("Unable to load audio file"), | |||||
| nullptr); | |||||
| else | else | ||||
| thumbnailComp.setCurrentURL (u); | thumbnailComp.setCurrentURL (u); | ||||
| } | } | ||||
| @@ -529,10 +529,13 @@ private: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::WarningIcon, "Enable Code Signing", | |||||
| "You need to enable code-signing for your iOS project and enable \"iCloud Documents\" " | |||||
| "permissions to be able to open audio files on your iDevice. See: " | |||||
| "https://forum.juce.com/t/native-ios-android-file-choosers"); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::WarningIcon) | |||||
| .withTitle ("Enable Code Signing") | |||||
| .withMessage ("You need to enable code-signing for your iOS project and enable \"iCloud Documents\" " | |||||
| "permissions to be able to open audio files on your iDevice. See: " | |||||
| "https://forum.juce.com/t/native-ios-android-file-choosers"), | |||||
| nullptr); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -359,11 +359,11 @@ private: | |||||
| fileToShare.deleteFile(); | fileToShare.deleteFile(); | ||||
| if (! success && error.isNotEmpty()) | if (! success && error.isNotEmpty()) | ||||
| { | |||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Sharing Error", | |||||
| error); | |||||
| } | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::WarningIcon) | |||||
| .withTitle ("Sharing Error") | |||||
| .withMessage (error), | |||||
| nullptr); | |||||
| }); | }); | ||||
| #endif | #endif | ||||
| @@ -524,7 +524,7 @@ private: | |||||
| void handleInvalidLegacyModeParameters() const | void handleInvalidLegacyModeParameters() const | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Invalid legacy mode channel layout", | "Invalid legacy mode channel layout", | ||||
| "Cannot set legacy mode start/end channel:\n" | "Cannot set legacy mode start/end channel:\n" | ||||
| "The end channel must not be less than the start channel!", | "The end channel must not be less than the start channel!", | ||||
| @@ -193,7 +193,7 @@ private: | |||||
| addAndMakeVisible (textButton); | addAndMakeVisible (textButton); | ||||
| shapeButton.setShape (getJUCELogoPath(), false, true, false); | shapeButton.setShape (getJUCELogoPath(), false, true, false); | ||||
| shapeButton.onClick = [] { AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Alert", "This is an AlertWindow"); }; | |||||
| shapeButton.onClick = [] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Alert", "This is an AlertWindow"); }; | |||||
| addAndMakeVisible (shapeButton); | addAndMakeVisible (shapeButton); | ||||
| } | } | ||||
| @@ -252,7 +252,7 @@ private: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Camera open failed", | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Camera open failed", | |||||
| "Camera open failed, reason: " + error); | "Camera open failed, reason: " + error); | ||||
| } | } | ||||
| @@ -365,7 +365,7 @@ private: | |||||
| void errorOccurred (const String& error) | void errorOccurred (const String& error) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| "Camera Device Error", | "Camera Device Error", | ||||
| "An error has occurred: " + error + " Camera will be closed."); | "An error has occurred: " + error + " Camera will be closed."); | ||||
| @@ -378,7 +378,7 @@ private: | |||||
| void sharingFinished (bool success, bool isCapture) | void sharingFinished (bool success, bool isCapture) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| isCapture ? "Image sharing result" : "Video sharing result", | isCapture ? "Image sharing result" : "Video sharing result", | ||||
| success ? "Success!" : "Failed!"); | success ? "Success!" : "Failed!"); | ||||
| @@ -89,19 +89,14 @@ public: | |||||
| // This method gets called on the message thread once our thread has finished.. | // This method gets called on the message thread once our thread has finished.. | ||||
| void threadComplete (bool userPressedCancel) override | void threadComplete (bool userPressedCancel) override | ||||
| { | { | ||||
| if (userPressedCancel) | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Progress window", | |||||
| "You pressed cancel!"); | |||||
| } | |||||
| else | |||||
| { | |||||
| // thread finished normally.. | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Progress window", | |||||
| "Thread finished ok!"); | |||||
| } | |||||
| const String messageString (userPressedCancel ? "You pressed cancel!" : "Thread finished ok!"); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Progress window") | |||||
| .withMessage (messageString) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| // ..and clean up by deleting our thread object.. | // ..and clean up by deleting our thread object.. | ||||
| delete this; | delete this; | ||||
| @@ -177,12 +172,13 @@ public: | |||||
| [] (bool granted) | [] (bool granted) | ||||
| { | { | ||||
| if (! granted) | if (! granted) | ||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Permissions warning", | |||||
| "External storage access permission not granted, some files" | |||||
| " may be inaccessible."); | |||||
| } | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::WarningIcon) | |||||
| .withTitle ("Permissions warning") | |||||
| .withMessage ("External storage access permission not granted, some files" | |||||
| " may be inaccessible.") | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -222,9 +218,12 @@ private: | |||||
| { | { | ||||
| void operator() (int result) const noexcept | void operator() (int result) const noexcept | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Alert Box", | |||||
| "Result code: " + String (result)); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Alert Box") | |||||
| .withMessage ("Result code: " + String (result)) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -246,10 +245,14 @@ private: | |||||
| auto optionIndexChosen = aw.getComboBoxComponent ("option")->getSelectedItemIndex(); | auto optionIndexChosen = aw.getComboBoxComponent ("option")->getSelectedItemIndex(); | ||||
| auto text = aw.getTextEditorContents ("text"); | auto text = aw.getTextEditorContents ("text"); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Alert Box", | |||||
| "Result code: " + String (result) + newLine | |||||
| + "Option index chosen: " + String (optionIndexChosen) + newLine | |||||
| + "Text: " + text); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Alert Box") | |||||
| .withMessage ("Result code: " + String (result) + newLine | |||||
| + "Option index chosen: " + String (optionIndexChosen) + newLine | |||||
| + "Text: " + text) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| } | } | ||||
| DialogsDemo& demo; | DialogsDemo& demo; | ||||
| @@ -259,11 +262,11 @@ private: | |||||
| { | { | ||||
| if (type >= plainAlertWindow && type <= questionAlertWindow) | if (type >= plainAlertWindow && type <= questionAlertWindow) | ||||
| { | { | ||||
| AlertWindow::AlertIconType icon = AlertWindow::NoIcon; | |||||
| MessageBoxIconType icon = MessageBoxIconType::NoIcon; | |||||
| if (type == warningAlertWindow) icon = AlertWindow::WarningIcon; | |||||
| if (type == infoAlertWindow) icon = AlertWindow::InfoIcon; | |||||
| if (type == questionAlertWindow) icon = AlertWindow::QuestionIcon; | |||||
| if (type == warningAlertWindow) icon = MessageBoxIconType::WarningIcon; | |||||
| if (type == infoAlertWindow) icon = MessageBoxIconType::InfoIcon; | |||||
| if (type == questionAlertWindow) icon = MessageBoxIconType::QuestionIcon; | |||||
| AlertWindow::showMessageBoxAsync (icon, "This is an AlertWindow", | AlertWindow::showMessageBoxAsync (icon, "This is an AlertWindow", | ||||
| "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", | "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", | ||||
| @@ -271,7 +274,7 @@ private: | |||||
| } | } | ||||
| else if (type == okCancelAlertWindow) | else if (type == okCancelAlertWindow) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, "This is an ok/cancel AlertWindow", | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon, "This is an ok/cancel AlertWindow", | |||||
| "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", | "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", | ||||
| {}, {}, {}, | {}, {}, {}, | ||||
| ModalCallbackFunction::create (AlertBoxResultChosen{})); | ModalCallbackFunction::create (AlertBoxResultChosen{})); | ||||
| @@ -291,7 +294,7 @@ private: | |||||
| { | { | ||||
| asyncAlertWindow = std::make_unique<AlertWindow> ("AlertWindow demo..", | asyncAlertWindow = std::make_unique<AlertWindow> ("AlertWindow demo..", | ||||
| "This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.", | "This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.", | ||||
| AlertWindow::QuestionIcon); | |||||
| MessageBoxIconType::QuestionIcon); | |||||
| asyncAlertWindow->addTextEditor ("text", "enter some text here", "text field:"); | asyncAlertWindow->addTextEditor ("text", "enter some text here", "text field:"); | ||||
| asyncAlertWindow->addComboBox ("option", { "option 1", "option 2", "option 3", "option 4" }, "some options"); | asyncAlertWindow->addComboBox ("option", { "option 1", "option 2", "option 3", "option 4" }, "some options"); | ||||
| @@ -326,9 +329,12 @@ private: | |||||
| chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() | chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() | ||||
| : result.toString (false)) << "\n"; | : result.toString (false)) << "\n"; | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "File Chooser...", | |||||
| "You picked: " + chosen); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("File Chooser...") | |||||
| .withMessage ("You picked: " + chosen) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| else if (type == loadWithPreviewChooser) | else if (type == loadWithPreviewChooser) | ||||
| @@ -349,9 +355,12 @@ private: | |||||
| chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() | chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() | ||||
| : result.toString (false)) << "\n"; | : result.toString (false)) << "\n"; | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "File Chooser...", | |||||
| "You picked: " + chosen); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("File Chooser...") | |||||
| .withMessage ("You picked: " + chosen) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }, | }, | ||||
| &imagePreview); | &imagePreview); | ||||
| } | } | ||||
| @@ -401,9 +410,12 @@ private: | |||||
| } | } | ||||
| #endif | #endif | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "File Chooser...", | |||||
| "You picked: " + name); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("File Chooser...") | |||||
| .withMessage ("You picked: " + name) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| else if (type == directoryChooser) | else if (type == directoryChooser) | ||||
| @@ -420,9 +432,12 @@ private: | |||||
| auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName() | auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName() | ||||
| : result.toString (true); | : result.toString (true); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "File Chooser...", | |||||
| "You picked: " + name); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("File Chooser...") | |||||
| .withMessage ("You picked: " + name) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| @@ -433,8 +448,12 @@ private: | |||||
| { | { | ||||
| auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); | auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Sharing Text Result", | |||||
| "Sharing text finished\nwith " + resultString); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Sharing Text Result") | |||||
| .withMessage ("Sharing text finished\nwith " + resultString) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| else if (type == shareFile) | else if (type == shareFile) | ||||
| @@ -454,9 +473,12 @@ private: | |||||
| { | { | ||||
| auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); | auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Sharing Files Result", | |||||
| "Sharing files finished\nwith " + resultString); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Sharing Files Result") | |||||
| .withMessage ("Sharing files finished\nwith " + resultString) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -480,8 +502,12 @@ private: | |||||
| String resultString = success ? String ("success") | String resultString = success ? String ("success") | ||||
| : ("failure\n (error: " + error + ")"); | : ("failure\n (error: " + error + ")"); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Sharing Images Result", | |||||
| "Sharing images finished\nwith " + resultString); | |||||
| AlertWindow::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Sharing Images Result") | |||||
| .withMessage ("Sharing images finished\nwith " + resultString) | |||||
| .withButton ("OK"), | |||||
| nullptr); | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| @@ -61,7 +61,7 @@ public: | |||||
| void buttonClicked() override | void buttonClicked() override | ||||
| { | { | ||||
| ++counter; | ++counter; | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "Action Button Pressed", | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Action Button Pressed", | |||||
| "Pressing this type of property component can trigger an action such as showing an alert window!"); | "Pressing this type of property component can trigger an action such as showing an alert window!"); | ||||
| refresh(); | refresh(); | ||||
| } | } | ||||
| @@ -134,7 +134,7 @@ private: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Couldn't load the file!", | "Couldn't load the file!", | ||||
| result.getErrorMessage()); | result.getErrorMessage()); | ||||
| } | } | ||||
| @@ -354,7 +354,7 @@ public: | |||||
| { | { | ||||
| if (! granted) | if (! granted) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Permissions warning", | "Permissions warning", | ||||
| "External storage access permission not granted, some files" | "External storage access permission not granted, some files" | ||||
| " may be inaccessible."); | " may be inaccessible."); | ||||
| @@ -503,7 +503,7 @@ private: | |||||
| void askIfUseNativeControls (const URL& url) | void askIfUseNativeControls (const URL& url) | ||||
| { | { | ||||
| auto* aw = new AlertWindow ("Choose viewer type", {}, AlertWindow::NoIcon); | |||||
| auto* aw = new AlertWindow ("Choose viewer type", {}, MessageBoxIconType::NoIcon); | |||||
| aw->addButton ("Yes", 1, KeyPress (KeyPress::returnKey)); | aw->addButton ("Yes", 1, KeyPress (KeyPress::returnKey)); | ||||
| aw->addButton ("No", 0, KeyPress (KeyPress::escapeKey)); | aw->addButton ("No", 0, KeyPress (KeyPress::escapeKey)); | ||||
| @@ -559,7 +559,7 @@ private: | |||||
| void showVideoUrlPrompt() | void showVideoUrlPrompt() | ||||
| { | { | ||||
| auto* aw = new AlertWindow ("Enter URL for video to load", {}, AlertWindow::NoIcon); | |||||
| auto* aw = new AlertWindow ("Enter URL for video to load", {}, MessageBoxIconType::NoIcon); | |||||
| aw->addButton ("OK", 1, KeyPress (KeyPress::returnKey)); | aw->addButton ("OK", 1, KeyPress (KeyPress::returnKey)); | ||||
| aw->addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey)); | aw->addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey)); | ||||
| @@ -596,7 +596,7 @@ private: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Couldn't load the file!", | "Couldn't load the file!", | ||||
| result.getErrorMessage()); | result.getErrorMessage()); | ||||
| } | } | ||||
| @@ -677,7 +677,7 @@ private: | |||||
| void errorOccurred (const String& errorMessage) | void errorOccurred (const String& errorMessage) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| "An error has occurred", | "An error has occurred", | ||||
| errorMessage + ", video will be unloaded."); | errorMessage + ", video will be unloaded."); | ||||
| @@ -156,7 +156,7 @@ private: | |||||
| voiceProduct.purchasePrice = "In-App purchases unavailable"; | voiceProduct.purchasePrice = "In-App purchases unavailable"; | ||||
| } | } | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "In-app purchase is unavailable!", | "In-app purchase is unavailable!", | ||||
| "In-App purchases are not available. This either means you are trying " | "In-App purchases are not available. This either means you are trying " | ||||
| "to use IAP on a platform that does not support IAP or you haven't setup " | "to use IAP on a platform that does not support IAP or you haven't setup " | ||||
| @@ -178,7 +178,7 @@ private: | |||||
| } | } | ||||
| } | } | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Your credit card will be charged!", | "Your credit card will be charged!", | ||||
| "You are running the sample code for JUCE In-App purchases. " | "You are running the sample code for JUCE In-App purchases. " | ||||
| "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!", | "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!", | ||||
| @@ -222,7 +222,7 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| void showConnectionErrorMessage (const String& messageText) | void showConnectionErrorMessage (const String& messageText) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Connection error", | "Connection error", | ||||
| messageText, | messageText, | ||||
| "OK"); | "OK"); | ||||
| @@ -273,7 +273,7 @@ private: | |||||
| void showConnectionErrorMessage (const String& messageText) | void showConnectionErrorMessage (const String& messageText) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Connection error", | "Connection error", | ||||
| messageText, | messageText, | ||||
| "OK"); | "OK"); | ||||
| @@ -403,7 +403,7 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| void handleConnectError (int failedPort) | void handleConnectError (int failedPort) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "OSC Connection error", | "OSC Connection error", | ||||
| "Error: could not connect to port " + String (failedPort), | "Error: could not connect to port " + String (failedPort), | ||||
| "OK"); | "OK"); | ||||
| @@ -412,7 +412,7 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| void handleDisconnectError() | void handleDisconnectError() | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Unknown error", | "Unknown error", | ||||
| "An unknown error occurred while trying to disconnect from UDP port.", | "An unknown error occurred while trying to disconnect from UDP port.", | ||||
| "OK"); | "OK"); | ||||
| @@ -421,7 +421,7 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| void handleInvalidPortNumberEntered() | void handleInvalidPortNumberEntered() | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Invalid port number", | "Invalid port number", | ||||
| "Error: you have entered an invalid UDP port number.", | "Error: you have entered an invalid UDP port number.", | ||||
| "OK"); | "OK"); | ||||
| @@ -194,7 +194,11 @@ public: | |||||
| if (token.isEmpty()) | if (token.isEmpty()) | ||||
| showRemoteInstructions(); | showRemoteInstructions(); | ||||
| else | else | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Device token", token); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Device token") | |||||
| .withMessage (token), | |||||
| nullptr); | |||||
| }; | }; | ||||
| #if JUCE_ANDROID | #if JUCE_ANDROID | ||||
| @@ -308,11 +312,11 @@ private: | |||||
| String requiredFields = "all required fields"; | String requiredFields = "all required fields"; | ||||
| #endif | #endif | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Incorrect notifications setup", | |||||
| "Please make sure that " | |||||
| + requiredFields + " are set."); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Incorrect notifications setup") | |||||
| .withMessage ("Please make sure that " + requiredFields + " are set."), | |||||
| nullptr); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -559,11 +563,13 @@ private: | |||||
| { | { | ||||
| ignoreUnused (isLocalNotification); | ignoreUnused (isLocalNotification); | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Received notification", | |||||
| "ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Received notification") | |||||
| .withMessage ("ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body), | |||||
| nullptr); | |||||
| } | } | ||||
| void handleNotificationAction (bool isLocalNotification, | void handleNotificationAction (bool isLocalNotification, | ||||
| @@ -573,24 +579,28 @@ private: | |||||
| { | { | ||||
| ignoreUnused (isLocalNotification); | ignoreUnused (isLocalNotification); | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Received notification action", | |||||
| "ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body | |||||
| + ", action: " + actionIdentifier | |||||
| + ", optionalResponse: " + optionalResponse); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Received notification action") | |||||
| .withMessage ("ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body | |||||
| + ", action: " + actionIdentifier | |||||
| + ", optionalResponse: " + optionalResponse), | |||||
| nullptr); | |||||
| PushNotifications::getInstance()->removeDeliveredNotification (n.identifier); | PushNotifications::getInstance()->removeDeliveredNotification (n.identifier); | ||||
| } | } | ||||
| void localNotificationDismissedByUser (const PushNotifications::Notification& n) override | void localNotificationDismissedByUser (const PushNotifications::Notification& n) override | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Notification dismissed by a user", | |||||
| "ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Notification dismissed by a user") | |||||
| .withMessage ("ID: " + n.identifier | |||||
| + ", title: " + n.title | |||||
| + ", body: " + n.body), | |||||
| nullptr); | |||||
| } | } | ||||
| void deliveredNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override | void deliveredNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override | ||||
| @@ -600,7 +610,11 @@ private: | |||||
| for (auto& n : notifs) | for (auto& n : notifs) | ||||
| text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; | text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Received notification list", text); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Received notification list") | |||||
| .withMessage (text), | |||||
| nullptr); | |||||
| } | } | ||||
| void pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override | void pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>& notifs) override | ||||
| @@ -610,37 +624,49 @@ private: | |||||
| for (auto& n : notifs) | for (auto& n : notifs) | ||||
| text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; | text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Pending notification list", text); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Pending notification list") | |||||
| .withMessage (text), | |||||
| nullptr); | |||||
| } | } | ||||
| void deviceTokenRefreshed (const String& token) override | void deviceTokenRefreshed (const String& token) override | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Device token refreshed", | |||||
| token); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Device token refreshed") | |||||
| .withMessage (token), | |||||
| nullptr); | |||||
| } | } | ||||
| #if JUCE_ANDROID | #if JUCE_ANDROID | ||||
| void remoteNotificationsDeleted() override | void remoteNotificationsDeleted() override | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Remote notifications deleted", | |||||
| "Some of the pending messages were removed!"); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Remote notifications deleted") | |||||
| .withMessage ("Some of the pending messages were removed!"), | |||||
| nullptr); | |||||
| } | } | ||||
| void upstreamMessageSent (const String& messageId) override | void upstreamMessageSent (const String& messageId) override | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Upstream message sent", | |||||
| "Message id: " + messageId); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Upstream message sent") | |||||
| .withMessage ("Message id: " + messageId), | |||||
| nullptr); | |||||
| } | } | ||||
| void upstreamMessageSendingError (const String& messageId, const String& error) override | void upstreamMessageSendingError (const String& messageId, const String& error) override | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Upstream message sending error", | |||||
| "Message id: " + messageId | |||||
| + "\nerror: " + error); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Upstream message sending error") | |||||
| .withMessage ("Message id: " + messageId | |||||
| + "\nerror: " + error), | |||||
| nullptr); | |||||
| } | } | ||||
| static Array<PushNotifications::Channel> getAndroidChannels() | static Array<PushNotifications::Channel> getAndroidChannels() | ||||
| @@ -1191,12 +1217,14 @@ private: | |||||
| static void showRemoteInstructions() | static void showRemoteInstructions() | ||||
| { | { | ||||
| #if JUCE_IOS || JUCE_MAC | #if JUCE_IOS || JUCE_MAC | ||||
| NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "Remote Notifications instructions", | |||||
| "In order to be able to test remote notifications " | |||||
| "ensure that the app is signed and that you register " | |||||
| "the bundle ID for remote notifications in " | |||||
| "Apple Developer Center."); | |||||
| NativeMessageBox::showAsync (MessageBoxOptions() | |||||
| .withIconType (MessageBoxIconType::InfoIcon) | |||||
| .withTitle ("Remote Notifications instructions") | |||||
| .withMessage ("In order to be able to test remote notifications " | |||||
| "ensure that the app is signed and that you register " | |||||
| "the bundle ID for remote notifications in " | |||||
| "Apple Developer Center."), | |||||
| nullptr); | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -98,7 +98,7 @@ void PluginGraph::addPluginCallback (std::unique_ptr<AudioPluginInstance> instan | |||||
| { | { | ||||
| if (instance == nullptr) | if (instance == nullptr) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Couldn't create plugin"), | TRANS("Couldn't create plugin"), | ||||
| error); | error); | ||||
| } | } | ||||
| @@ -222,7 +222,7 @@ File NewProjectWizard::getLastWizardFolder() | |||||
| static void displayFailedFilesMessage (const StringArray& failedFiles) | static void displayFailedFilesMessage (const StringArray& failedFiles) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Errors in Creating Project!"), | TRANS("Errors in Creating Project!"), | ||||
| TRANS("The following files couldn't be written:") | TRANS("The following files couldn't be written:") | ||||
| + "\n\n" | + "\n\n" | ||||
| @@ -244,7 +244,7 @@ static void prepareDirectory (const File& targetFolder, Callback&& callback) | |||||
| } | } | ||||
| else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder)) | else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder)) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::InfoIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::InfoIcon, | |||||
| TRANS("New JUCE Project"), | TRANS("New JUCE Project"), | ||||
| TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName()) | TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName()) | ||||
| + TRANS("This folder isn't empty - are you sure you want to create the project there?") | + TRANS("This folder isn't empty - are you sure you want to create the project there?") | ||||
| @@ -122,7 +122,7 @@ private: | |||||
| if (postStrings.size() != preStrings.size()) | if (postStrings.size() != preStrings.size()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Error"), | TRANS("Error"), | ||||
| TRANS("The pre- and post-translation text doesn't match!\n\n" | TRANS("The pre- and post-translation text doesn't match!\n\n" | ||||
| "Perhaps it got mangled by the translator?")); | "Perhaps it got mangled by the translator?")); | ||||
| @@ -138,7 +138,7 @@ private: | |||||
| if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject()) | if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject()) | ||||
| setPreTranslationText (TranslationHelpers::getPreTranslationText (*project)); | setPreTranslationText (TranslationHelpers::getPreTranslationText (*project)); | ||||
| else | else | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Translation Tool", | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool", | |||||
| "This will only work when you have a project open!"); | "This will only work when you have a project open!"); | ||||
| } | } | ||||
| @@ -835,7 +835,7 @@ void ProjucerApplication::launchDemoRunner() | |||||
| "Couldn't find a compiled version of the Demo Runner." | "Couldn't find a compiled version of the Demo Runner." | ||||
| " Please compile the Demo Runner project in the JUCE examples directory.", | " Please compile the Demo Runner project in the JUCE examples directory.", | ||||
| "OK", {}, {}, | "OK", {}, {}, | ||||
| AlertWindow::WarningIcon, 1, | |||||
| MessageBoxIconType::WarningIcon, 1, | |||||
| mainWindowList.getFrontmostWindow (false))); | mainWindowList.getFrontmostWindow (false))); | ||||
| demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int) | demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int) | ||||
| { | { | ||||
| @@ -847,7 +847,7 @@ void ProjucerApplication::launchDemoRunner() | |||||
| "Couldn't find a compiled version of the Demo Runner." | "Couldn't find a compiled version of the Demo Runner." | ||||
| " Do you want to open the project?", | " Do you want to open the project?", | ||||
| "Open project", "Cancel", {}, | "Open project", "Cancel", {}, | ||||
| AlertWindow::QuestionIcon, 2, | |||||
| MessageBoxIconType::QuestionIcon, 2, | |||||
| mainWindowList.getFrontmostWindow (false))); | mainWindowList.getFrontmostWindow (false))); | ||||
| demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal) | demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal) | ||||
| { | { | ||||
| @@ -1102,7 +1102,7 @@ void ProjucerApplication::createNewProjectFromClipboard() | |||||
| { | { | ||||
| if (errorString.isNotEmpty()) | if (errorString.isNotEmpty()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", errorString); | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Error", errorString); | |||||
| tempFile.deleteFile(); | tempFile.deleteFile(); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -56,7 +56,7 @@ void LatestVersionCheckerAndUpdater::run() | |||||
| if (info == nullptr) | if (info == nullptr) | ||||
| { | { | ||||
| if (! backgroundCheck) | if (! backgroundCheck) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Update Server Communication Error", | "Update Server Communication Error", | ||||
| "Failed to communicate with the JUCE update server.\n" | "Failed to communicate with the JUCE update server.\n" | ||||
| "Please try again in a few minutes.\n\n" | "Please try again in a few minutes.\n\n" | ||||
| @@ -68,7 +68,7 @@ void LatestVersionCheckerAndUpdater::run() | |||||
| if (! info->isNewerVersionThanCurrent()) | if (! info->isNewerVersionThanCurrent()) | ||||
| { | { | ||||
| if (! backgroundCheck) | if (! backgroundCheck) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| "No New Version Available", | "No New Version Available", | ||||
| "Your JUCE version is up to date."); | "Your JUCE version is up to date."); | ||||
| return; | return; | ||||
| @@ -109,7 +109,7 @@ void LatestVersionCheckerAndUpdater::run() | |||||
| } | } | ||||
| if (! backgroundCheck) | if (! backgroundCheck) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Failed to find any new downloads", | "Failed to find any new downloads", | ||||
| "Please try again in a few minutes."); | "Please try again in a few minutes."); | ||||
| } | } | ||||
| @@ -275,13 +275,13 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version | |||||
| { | { | ||||
| if (targetFolder.getChildFile (".git").isDirectory()) | if (targetFolder.getChildFile (".git").isDirectory()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version", | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Downloading New JUCE Version", | |||||
| targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); | targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); | ||||
| return; | return; | ||||
| } | } | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| "Overwrite Existing JUCE Folder?", | "Overwrite Existing JUCE Folder?", | ||||
| "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" | "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" | ||||
| "This will move the existing folder to " + targetFolderPath + "_old.\n\n" | "This will move the existing folder to " + targetFolderPath + "_old.\n\n" | ||||
| @@ -295,7 +295,7 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version | |||||
| if (targetFolder.exists()) | if (targetFolder.exists()) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| "Existing File Or Directory", | "Existing File Or Directory", | ||||
| "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?", | "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?", | ||||
| {}, | {}, | ||||
| @@ -388,7 +388,7 @@ private: | |||||
| result = install (zipData); | result = install (zipData); | ||||
| if (result.failed()) | if (result.failed()) | ||||
| MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Installation Failed", | "Installation Failed", | ||||
| result.getErrorMessage()); }); | result.getErrorMessage()); }); | ||||
| else | else | ||||
| @@ -452,7 +452,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba | |||||
| if (generatorResult != Result::ok()) | if (generatorResult != Result::ok()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "PIP Error.", | "PIP Error.", | ||||
| generatorResult.getErrorMessage()); | generatorResult.getErrorMessage()); | ||||
| @@ -464,7 +464,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba | |||||
| if (! generator->createMainCpp()) | if (! generator->createMainCpp()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "PIP Error.", | "PIP Error.", | ||||
| "Failed to create Main.cpp."); | "Failed to create Main.cpp."); | ||||
| @@ -481,7 +481,7 @@ void MainWindow::openPIP (const File& pipFile, std::function<void (bool)> callba | |||||
| if (! openedSuccessfully) | if (! openedSuccessfully) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "PIP Error.", | "PIP Error.", | ||||
| "Failed to open .jucer file."); | "Failed to open .jucer file."); | ||||
| @@ -176,7 +176,7 @@ void OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Docume | |||||
| return; | return; | ||||
| } | } | ||||
| AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon, | |||||
| AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon, | |||||
| TRANS("Closing document..."), | TRANS("Closing document..."), | ||||
| TRANS("Do you want to save the changes to \"") | TRANS("Do you want to save the changes to \"") | ||||
| + doc->getName() + "\"?", | + doc->getName() + "\"?", | ||||
| @@ -658,7 +658,7 @@ void CppCodeEditorComponent::insertComponentClass() | |||||
| { | { | ||||
| asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Insert a new Component class"), | asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Insert a new Component class"), | ||||
| TRANS ("Please enter a name for the new class"), | TRANS ("Please enter a name for the new class"), | ||||
| AlertWindow::NoIcon, | |||||
| MessageBoxIconType::NoIcon, | |||||
| nullptr); | nullptr); | ||||
| const String classNameField { "Class Name" }; | const String classNameField { "Class Name" }; | ||||
| @@ -265,7 +265,7 @@ void ResourceEditorPanel::reloadAll() | |||||
| failed.add (document.getResources().getResourceNames() [i]); | failed.add (document.getResources().getResourceNames() [i]); | ||||
| if (failed.size() > 0) | if (failed.size() > 0) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Reloading resources"), | TRANS("Reloading resources"), | ||||
| TRANS("The following resources couldn't be reloaded from their original files:\n\n") | TRANS("The following resources couldn't be reloaded from their original files:\n\n") | ||||
| + failed.joinIntoString (", ")); | + failed.joinIntoString (", ")); | ||||
| @@ -143,7 +143,7 @@ void BinaryResources::browseForResource (const String& title, | |||||
| if (! add (name, fc.getResult())) | if (! add (name, fc.getResult())) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Adding Resource"), | TRANS("Adding Resource"), | ||||
| TRANS("Failed to load the file!")); | TRANS("Failed to load the file!")); | ||||
| @@ -682,14 +682,14 @@ void EnabledModulesList::addModuleOfferingToCopy (const File& f, bool isFromUser | |||||
| if (! m.isValid()) | if (! m.isValid()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| "Add Module", "This wasn't a valid module folder!"); | "Add Module", "This wasn't a valid module folder!"); | ||||
| return; | return; | ||||
| } | } | ||||
| if (isModuleEnabled (m.getID())) | if (isModuleEnabled (m.getID())) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| "Add Module", "The project already contains this module!"); | "Add Module", "The project already contains this module!"); | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -90,7 +90,7 @@ public: | |||||
| safeThis->project.getUndoManagerFor (parent)); | safeThis->project.getUndoManagerFor (parent)); | ||||
| }; | }; | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| "Delete Exporter", | "Delete Exporter", | ||||
| "Are you sure you want to delete this export target?", | "Are you sure you want to delete this export target?", | ||||
| "", | "", | ||||
| @@ -244,7 +244,7 @@ public: | |||||
| void deleteItem() override | void deleteItem() override | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| "Delete Configuration", | "Delete Configuration", | ||||
| "Are you sure you want to delete this configuration?", | "Are you sure you want to delete this configuration?", | ||||
| "", | "", | ||||
| @@ -138,7 +138,7 @@ public: | |||||
| if (filesToTrash.size() > maxFilesToList) | if (filesToTrash.size() > maxFilesToList) | ||||
| fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files..."; | fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files..."; | ||||
| AlertWindow::showYesNoCancelBox (AlertWindow::NoIcon, | |||||
| AlertWindow::showYesNoCancelBox (MessageBoxIconType::NoIcon, | |||||
| "Delete Project Items", | "Delete Project Items", | ||||
| "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n" | "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n" | ||||
| + fileList, | + fileList, | ||||
| @@ -521,7 +521,7 @@ public: | |||||
| { | { | ||||
| if (newName != File::createLegalFileName (newName)) | if (newName != File::createLegalFileName (newName)) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "File Rename", | "File Rename", | ||||
| "That filename contained some illegal characters!"); | "That filename contained some illegal characters!"); | ||||
| triggerAsyncRename (item); | triggerAsyncRename (item); | ||||
| @@ -538,7 +538,7 @@ public: | |||||
| if (correspondingItem.isValid()) | if (correspondingItem.isValid()) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::NoIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::NoIcon, | |||||
| "File Rename", | "File Rename", | ||||
| "Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?", | "Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?", | ||||
| {}, | {}, | ||||
| @@ -552,7 +552,7 @@ public: | |||||
| if (! parent->item.renameFile (newFile)) | if (! parent->item.renameFile (newFile)) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "File Rename", | "File Rename", | ||||
| "Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); | "Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); | ||||
| return; | return; | ||||
| @@ -560,7 +560,7 @@ public: | |||||
| if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension()))) | if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension()))) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "File Rename", | "File Rename", | ||||
| "Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); | "Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); | ||||
| } | } | ||||
| @@ -571,7 +571,7 @@ public: | |||||
| if (! item.renameFile (newFile)) | if (! item.renameFile (newFile)) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "File Rename", | "File Rename", | ||||
| "Failed to rename the file!\n\nCheck your file permissions!"); | "Failed to rename the file!\n\nCheck your file permissions!"); | ||||
| } | } | ||||
| @@ -378,7 +378,7 @@ private: | |||||
| { | { | ||||
| missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID); | missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID); | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Adding Missing Dependencies", | "Adding Missing Dependencies", | ||||
| "Couldn't locate some of these modules - you'll need to find their " | "Couldn't locate some of these modules - you'll need to find their " | ||||
| "folders manually and add them to the list."); | "folders manually and add them to the list."); | ||||
| @@ -320,7 +320,7 @@ void ProjectContentComponent::closeDocument() | |||||
| static void showSaveWarning (OpenDocumentManager::Document* currentDocument) | static void showSaveWarning (OpenDocumentManager::Document* currentDocument) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Save failed!"), | TRANS("Save failed!"), | ||||
| TRANS("Couldn't save the file:") | TRANS("Couldn't save the file:") | ||||
| + "\n" + currentDocument->getFile().getFullPathName()); | + "\n" + currentDocument->getFile().getFullPathName()); | ||||
| @@ -407,7 +407,7 @@ void Project::removeDefunctExporters() | |||||
| if (ProjucerApplication::getApp().isRunningCommandLine) | if (ProjucerApplication::getApp().isRunningCommandLine) | ||||
| std::cout << "WARNING! The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project." << std::endl; | std::cout << "WARNING! The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project." << std::endl; | ||||
| else | else | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS (oldExporters[key]), | TRANS (oldExporters[key]), | ||||
| TRANS ("The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project.")); | TRANS ("The " + oldExporters[key] + " Exporter is deprecated. The exporter will be removed from this project.")); | ||||
| @@ -723,7 +723,7 @@ public: | |||||
| "Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX/RTAS Binary Location\" in the Xcode (OS X) configuration settings.\n\n" | "Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX/RTAS Binary Location\" in the Xcode (OS X) configuration settings.\n\n" | ||||
| "Click 'Update' to remove the script (otherwise your plug-in may not compile correctly)."; | "Click 'Update' to remove the script (otherwise your plug-in may not compile correctly)."; | ||||
| if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| if (AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| "Project settings: " + project.getDocumentTitle(), | "Project settings: " + project.getDocumentTitle(), | ||||
| alertWindowText, "Update", "Cancel", nullptr, nullptr)) | alertWindowText, "Update", "Cancel", nullptr, nullptr)) | ||||
| postbuildCommandValue.resetToDefault(); | postbuildCommandValue.resetToDefault(); | ||||
| @@ -171,7 +171,7 @@ private: | |||||
| { | { | ||||
| asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Create new Component class"), | asyncAlertWindow = std::make_unique<AlertWindow> (TRANS ("Create new Component class"), | ||||
| TRANS ("Please enter the name for the new class"), | TRANS ("Please enter the name for the new class"), | ||||
| AlertWindow::NoIcon, nullptr); | |||||
| MessageBoxIconType::NoIcon, nullptr); | |||||
| asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false); | asyncAlertWindow->addTextEditor (getClassNameFieldName(), String(), String(), false); | ||||
| asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey)); | asyncAlertWindow->addButton (TRANS ("Create Files"), 1, KeyPress (KeyPress::returnKey)); | ||||
| @@ -235,7 +235,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| void NewFileWizard::Type::showFailedToWriteMessage (const File& file) | void NewFileWizard::Type::showFailedToWriteMessage (const File& file) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| "Failed to Create File!", | "Failed to Create File!", | ||||
| "Couldn't write to the file: " + file.getFullPathName()); | "Couldn't write to the file: " + file.getFullPathName()); | ||||
| } | } | ||||
| @@ -388,8 +388,8 @@ public: | |||||
| PropertiesFile* properties, bool allowPluginsWhichRequireAsynchronousInstantiation, int threads, | PropertiesFile* properties, bool allowPluginsWhichRequireAsynchronousInstantiation, int threads, | ||||
| const String& title, const String& text) | const String& title, const String& text) | ||||
| : owner (plc), formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties), | : owner (plc), formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties), | ||||
| pathChooserWindow (TRANS("Select folders to scan..."), String(), AlertWindow::NoIcon), | |||||
| progressWindow (title, text, AlertWindow::NoIcon), | |||||
| pathChooserWindow (TRANS("Select folders to scan..."), String(), MessageBoxIconType::NoIcon), | |||||
| progressWindow (title, text, MessageBoxIconType::NoIcon), | |||||
| numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation) | numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation) | ||||
| { | { | ||||
| FileSearchPath path (formatToScan.getDefaultLocationsToSearch()); | FileSearchPath path (formatToScan.getDefaultLocationsToSearch()); | ||||
| @@ -467,7 +467,7 @@ private: | |||||
| if (isStupidPath (f)) | if (isStupidPath (f)) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Plugin Scanning"), | TRANS("Plugin Scanning"), | ||||
| TRANS("If you choose to scan folders that contain non-plugin files, " | TRANS("If you choose to scan folders that contain non-plugin files, " | ||||
| "then scanning may take a long time, and can cause crashes when " | "then scanning may take a long time, and can cause crashes when " | ||||
| @@ -642,7 +642,7 @@ void PluginListComponent::scanFinished (const StringArray& failedFiles) | |||||
| currentScanner.reset(); // mustn't delete this before using the failed files array | currentScanner.reset(); // mustn't delete this before using the failed files array | ||||
| if (shortNames.size() > 0) | if (shortNames.size() > 0) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| TRANS("Scan complete"), | TRANS("Scan complete"), | ||||
| TRANS("Note that the following files appeared to be plugin files, but failed to load correctly") | TRANS("Note that the following files appeared to be plugin files, but failed to load correctly") | ||||
| + ":\n\n" | + ":\n\n" | ||||
| @@ -405,7 +405,7 @@ public: | |||||
| } | } | ||||
| if (error.isNotEmpty()) | if (error.isNotEmpty()) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Error when trying to open audio device!"), | TRANS("Error when trying to open audio device!"), | ||||
| error); | error); | ||||
| } | } | ||||
| @@ -289,25 +289,4 @@ int ModalComponentManager::runEventLoopForCurrentComponent() | |||||
| } | } | ||||
| #endif | #endif | ||||
| //============================================================================== | |||||
| struct LambdaCallback : public ModalComponentManager::Callback | |||||
| { | |||||
| LambdaCallback (std::function<void (int)> fn) noexcept : function (fn) {} | |||||
| void modalStateFinished (int result) override | |||||
| { | |||||
| if (function != nullptr) | |||||
| function (result); | |||||
| } | |||||
| std::function<void (int)> function; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback) | |||||
| }; | |||||
| ModalComponentManager::Callback* ModalCallbackFunction::create (std::function<void (int)> f) | |||||
| { | |||||
| return new LambdaCallback (f); | |||||
| } | |||||
| } // namespace juce | } // namespace juce | ||||
| @@ -163,14 +163,26 @@ class JUCE_API ModalCallbackFunction | |||||
| { | { | ||||
| public: | public: | ||||
| /** This is a utility function to create a ModalComponentManager::Callback that will | /** This is a utility function to create a ModalComponentManager::Callback that will | ||||
| call a lambda function. | |||||
| call a callable object. | |||||
| The lambda that you supply must take an integer parameter, which is the result code that | |||||
| The function that you supply must take an integer parameter, which is the result code that | |||||
| was returned when the modal component was dismissed. | was returned when the modal component was dismissed. | ||||
| @see ModalComponentManager::Callback | @see ModalComponentManager::Callback | ||||
| */ | */ | ||||
| static ModalComponentManager::Callback* create (std::function<void (int)>); | |||||
| template <typename CallbackFn> | |||||
| static ModalComponentManager::Callback* create (CallbackFn&& fn) | |||||
| { | |||||
| struct Callable : public ModalComponentManager::Callback | |||||
| { | |||||
| explicit Callable (CallbackFn&& f) : fn (std::forward<CallbackFn> (f)) {} | |||||
| void modalStateFinished (int result) override { fn (result); } | |||||
| CallbackFn fn; | |||||
| }; | |||||
| return new Callable (std::forward<CallbackFn> (fn)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| /** This is a utility function to create a ModalComponentManager::Callback that will | /** This is a utility function to create a ModalComponentManager::Callback that will | ||||
| @@ -194,7 +194,7 @@ void FileChooserDialogBox::okButtonPressed() | |||||
| && content->chooserComponent.isSaveMode() | && content->chooserComponent.isSaveMode() | ||||
| && content->chooserComponent.getSelectedFile(0).exists()) | && content->chooserComponent.getSelectedFile(0).exists()) | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| TRANS("File already exists"), | TRANS("File already exists"), | ||||
| TRANS("There's already a file called: FLNM") | TRANS("There's already a file called: FLNM") | ||||
| .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName()) | .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName()) | ||||
| @@ -229,7 +229,7 @@ void FileChooserDialogBox::createNewFolder() | |||||
| { | { | ||||
| auto* aw = new AlertWindow (TRANS("New Folder"), | auto* aw = new AlertWindow (TRANS("New Folder"), | ||||
| TRANS("Please enter the name for the folder"), | TRANS("Please enter the name for the folder"), | ||||
| AlertWindow::NoIcon, this); | |||||
| MessageBoxIconType::NoIcon, this); | |||||
| aw->addTextEditor ("Folder Name", String(), String(), false); | aw->addTextEditor ("Folder Name", String(), String(), false); | ||||
| aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey)); | aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey)); | ||||
| @@ -251,7 +251,7 @@ void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialo | |||||
| auto parent = content->chooserComponent.getRoot(); | auto parent = content->chooserComponent.getRoot(); | ||||
| if (! parent.getChildFile (name).createDirectory()) | if (! parent.getChildFile (name).createDirectory()) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS ("New Folder"), | TRANS ("New Folder"), | ||||
| TRANS ("Couldn't create the folder!")); | TRANS ("Couldn't create the folder!")); | ||||
| @@ -66,6 +66,7 @@ | |||||
| #include <windowsx.h> | #include <windowsx.h> | ||||
| #include <vfw.h> | #include <vfw.h> | ||||
| #include <commdlg.h> | #include <commdlg.h> | ||||
| #include <commctrl.h> | |||||
| #if ! JUCE_MINGW | #if ! JUCE_MINGW | ||||
| #include <UIAutomation.h> | #include <UIAutomation.h> | ||||
| @@ -82,6 +83,7 @@ | |||||
| #elif ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | #elif ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | ||||
| #pragma comment(lib, "vfw32.lib") | #pragma comment(lib, "vfw32.lib") | ||||
| #pragma comment(lib, "imm32.lib") | #pragma comment(lib, "imm32.lib") | ||||
| #pragma comment(lib, "comctl32.lib") | |||||
| #if JUCE_OPENGL | #if JUCE_OPENGL | ||||
| #pragma comment(lib, "OpenGL32.Lib") | #pragma comment(lib, "OpenGL32.Lib") | ||||
| @@ -258,6 +258,7 @@ namespace juce | |||||
| #include "misc/juce_JUCESplashScreen.h" | #include "misc/juce_JUCESplashScreen.h" | ||||
| #include "widgets/juce_TreeView.h" | #include "widgets/juce_TreeView.h" | ||||
| #include "windows/juce_TopLevelWindow.h" | #include "windows/juce_TopLevelWindow.h" | ||||
| #include "windows/juce_MessageBoxOptions.h" | |||||
| #include "windows/juce_AlertWindow.h" | #include "windows/juce_AlertWindow.h" | ||||
| #include "windows/juce_CallOutBox.h" | #include "windows/juce_CallOutBox.h" | ||||
| #include "windows/juce_ComponentPeer.h" | #include "windows/juce_ComponentPeer.h" | ||||
| @@ -407,7 +407,7 @@ void LookAndFeel_V2::drawDrawableButton (Graphics& g, DrawableButton& button, | |||||
| //============================================================================== | //============================================================================== | ||||
| AlertWindow* LookAndFeel_V2::createAlertWindow (const String& title, const String& message, | AlertWindow* LookAndFeel_V2::createAlertWindow (const String& title, const String& message, | ||||
| const String& button1, const String& button2, const String& button3, | const String& button1, const String& button2, const String& button3, | ||||
| AlertWindow::AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| int numButtons, Component* associatedComponent) | int numButtons, Component* associatedComponent) | ||||
| { | { | ||||
| AlertWindow* aw = new AlertWindow (title, message, iconType, associatedComponent); | AlertWindow* aw = new AlertWindow (title, message, iconType, associatedComponent); | ||||
| @@ -457,13 +457,13 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert, | |||||
| const Rectangle<int> iconRect (iconSize / -10, iconSize / -10, | const Rectangle<int> iconRect (iconSize / -10, iconSize / -10, | ||||
| iconSize, iconSize); | iconSize, iconSize); | ||||
| if (alert.getAlertType() != AlertWindow::NoIcon) | |||||
| if (alert.getAlertType() != MessageBoxIconType::NoIcon) | |||||
| { | { | ||||
| Path icon; | Path icon; | ||||
| uint32 colour; | uint32 colour; | ||||
| char character; | char character; | ||||
| if (alert.getAlertType() == AlertWindow::WarningIcon) | |||||
| if (alert.getAlertType() == MessageBoxIconType::WarningIcon) | |||||
| { | { | ||||
| colour = 0x55ff5555; | colour = 0x55ff5555; | ||||
| character = '!'; | character = '!'; | ||||
| @@ -476,8 +476,8 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert, | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| colour = alert.getAlertType() == AlertWindow::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900; | |||||
| character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?'; | |||||
| colour = alert.getAlertType() == MessageBoxIconType::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900; | |||||
| character = alert.getAlertType() == MessageBoxIconType::InfoIcon ? 'i' : '?'; | |||||
| icon.addEllipse (iconRect.toFloat()); | icon.addEllipse (iconRect.toFloat()); | ||||
| } | } | ||||
| @@ -67,7 +67,7 @@ public: | |||||
| const String& button1, | const String& button1, | ||||
| const String& button2, | const String& button2, | ||||
| const String& button3, | const String& button3, | ||||
| AlertWindow::AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| int numButtons, Component* associatedComponent) override; | int numButtons, Component* associatedComponent) override; | ||||
| void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; | void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; | ||||
| @@ -385,7 +385,7 @@ void LookAndFeel_V4::changeToggleButtonWidthToFitText (ToggleButton& button) | |||||
| //============================================================================== | //============================================================================== | ||||
| AlertWindow* LookAndFeel_V4::createAlertWindow (const String& title, const String& message, | AlertWindow* LookAndFeel_V4::createAlertWindow (const String& title, const String& message, | ||||
| const String& button1, const String& button2, const String& button3, | const String& button1, const String& button2, const String& button3, | ||||
| AlertWindow::AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| int numButtons, Component* associatedComponent) | int numButtons, Component* associatedComponent) | ||||
| { | { | ||||
| auto boundsOffset = 50; | auto boundsOffset = 50; | ||||
| @@ -429,13 +429,13 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert, | |||||
| Rectangle<int> iconRect (iconSize / -10, iconSize / -10, | Rectangle<int> iconRect (iconSize / -10, iconSize / -10, | ||||
| iconSize, iconSize); | iconSize, iconSize); | ||||
| if (alert.getAlertType() != AlertWindow::NoIcon) | |||||
| if (alert.getAlertType() != MessageBoxIconType::NoIcon) | |||||
| { | { | ||||
| Path icon; | Path icon; | ||||
| char character; | char character; | ||||
| uint32 colour; | uint32 colour; | ||||
| if (alert.getAlertType() == AlertWindow::WarningIcon) | |||||
| if (alert.getAlertType() == MessageBoxIconType::WarningIcon) | |||||
| { | { | ||||
| character = '!'; | character = '!'; | ||||
| @@ -449,7 +449,7 @@ void LookAndFeel_V4::drawAlertBox (Graphics& g, AlertWindow& alert, | |||||
| else | else | ||||
| { | { | ||||
| colour = Colour (0xff00b0b9).withAlpha (0.4f).getARGB(); | colour = Colour (0xff00b0b9).withAlpha (0.4f).getARGB(); | ||||
| character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?'; | |||||
| character = alert.getAlertType() == MessageBoxIconType::InfoIcon ? 'i' : '?'; | |||||
| icon.addEllipse (iconRect.toFloat()); | icon.addEllipse (iconRect.toFloat()); | ||||
| } | } | ||||
| @@ -130,7 +130,7 @@ public: | |||||
| const String& button1, | const String& button1, | ||||
| const String& button2, | const String& button2, | ||||
| const String& button3, | const String& button3, | ||||
| AlertWindow::AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| int numButtons, Component* associatedComponent) override; | int numButtons, Component* associatedComponent) override; | ||||
| void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; | void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; | ||||
| @@ -1226,8 +1226,8 @@ DECLARE_JNI_CLASS (AndroidDialogOnClickListener, "android/content/DialogInterfac | |||||
| class DialogListener : public juce::AndroidInterfaceImplementer | class DialogListener : public juce::AndroidInterfaceImplementer | ||||
| { | { | ||||
| public: | public: | ||||
| DialogListener (ModalComponentManager::Callback* callbackToUse, int resultToUse) | |||||
| : callback (callbackToUse), result (resultToUse) | |||||
| DialogListener (std::shared_ptr<ModalComponentManager::Callback> callbackToUse, int resultToUse) | |||||
| : callback (std::move (callbackToUse)), result (resultToUse) | |||||
| {} | {} | ||||
| void onResult (jobject dialog) | void onResult (jobject dialog) | ||||
| @@ -1257,46 +1257,44 @@ private: | |||||
| return AndroidInterfaceImplementer::invoke (proxy, method, args); | return AndroidInterfaceImplementer::invoke (proxy, method, args); | ||||
| } | } | ||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| std::shared_ptr<ModalComponentManager::Callback> callback; | |||||
| int result; | int result; | ||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| static void createAndroidDialog (const String& title, const String& message, | |||||
| ModalComponentManager::Callback* callback, | |||||
| const String& positiveButton = {}, const String& negativeButton = {}, | |||||
| const String& neutralButton = {}) | |||||
| static void createAndroidDialog (const MessageBoxOptions& opts, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback) | |||||
| { | { | ||||
| auto* env = getEnv(); | auto* env = getEnv(); | ||||
| LocalRef<jobject> builder (env->NewObject (AndroidAlertDialogBuilder, AndroidAlertDialogBuilder.construct, getMainActivity().get())); | LocalRef<jobject> builder (env->NewObject (AndroidAlertDialogBuilder, AndroidAlertDialogBuilder.construct, getMainActivity().get())); | ||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setTitle, javaString (title).get())); | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setMessage, javaString (message).get())); | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setTitle, javaString (opts.getTitle()).get())); | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setMessage, javaString (opts.getMessage()).get())); | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setCancelable, true)); | builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setCancelable, true)); | ||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setOnCancelListener, | |||||
| CreateJavaInterface (new DialogListener (callback, 0), | |||||
| "android/content/DialogInterface$OnCancelListener").get())); | |||||
| std::shared_ptr<ModalComponentManager::Callback> sharedCallback (std::move (callback)); | |||||
| auto positiveButtonText = positiveButton.isEmpty() ? String ("OK") : positiveButton; | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setOnCancelListener, | |||||
| CreateJavaInterface (new DialogListener (sharedCallback, 0), | |||||
| "android/content/DialogInterface$OnCancelListener").get())); | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setPositiveButton, | builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setPositiveButton, | ||||
| javaString (positiveButtonText).get(), | |||||
| CreateJavaInterface (new DialogListener (callback, positiveButton.isEmpty() ? 0 : 1), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| javaString (opts.getButtonText (0)).get(), | |||||
| CreateJavaInterface (new DialogListener (sharedCallback, 0), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| if (negativeButton.isNotEmpty()) | |||||
| if (opts.getButtonText (1).isNotEmpty()) | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton, | builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton, | ||||
| javaString (negativeButton).get(), | |||||
| CreateJavaInterface (new DialogListener (callback, neutralButton.isEmpty() ? 0 : 2), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| javaString (opts.getButtonText (1)).get(), | |||||
| CreateJavaInterface (new DialogListener (sharedCallback, 1), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| if (neutralButton.isNotEmpty()) | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNegativeButton, | |||||
| javaString (neutralButton).get(), | |||||
| CreateJavaInterface (new DialogListener (callback, 0), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| if (opts.getButtonText (2).isNotEmpty()) | |||||
| builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.setNeutralButton, | |||||
| javaString (opts.getButtonText (2)).get(), | |||||
| CreateJavaInterface (new DialogListener (sharedCallback, 2), | |||||
| "android/content/DialogInterface$OnClickListener").get())); | |||||
| LocalRef<jobject> dialog (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.create)); | LocalRef<jobject> dialog (env->CallObjectMethod (builder.get(), AndroidAlertDialogBuilder.create)); | ||||
| @@ -1315,47 +1313,76 @@ static void createAndroidDialog (const String& title, const String& message, | |||||
| env->CallVoidMethod (window.get(), AndroidWindow.clearFlags, FLAG_NOT_FOCUSABLE); | env->CallVoidMethod (window.get(), AndroidWindow.clearFlags, FLAG_NOT_FOCUSABLE); | ||||
| } | } | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| createAndroidDialog (title, message, callback); | |||||
| showAsync (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")), | |||||
| AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)); | |||||
| } | } | ||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| jassert (callback != nullptr); // on android, all alerts must be non-modal!! | |||||
| showAsync (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)); | |||||
| createAndroidDialog (title, message, callback, "OK", "Cancel"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| jassert (callback != nullptr); // on android, all alerts must be non-modal!! | |||||
| showAsync (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)); | |||||
| createAndroidDialog (title, message, callback, "Yes", "No", "Cancel"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| const String& title, const String& message, | |||||
| Component* /*associatedComponent*/, | |||||
| ModalComponentManager::Callback* callback) | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | |||||
| Component* /*associatedComponent*/, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | { | ||||
| jassert (callback != nullptr); // on android, all alerts must be non-modal!! | |||||
| showAsync (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")), | |||||
| AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)); | |||||
| createAndroidDialog (title, message, callback, "Yes", "No"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | |||||
| createAndroidDialog (options, std::unique_ptr<ModalComponentManager::Callback> (callback)); | |||||
| } | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| static bool androidScreenSaverEnabled = true; | static bool androidScreenSaverEnabled = true; | ||||
| @@ -437,19 +437,18 @@ void LookAndFeel::playAlertSound() | |||||
| class iOSMessageBox | class iOSMessageBox | ||||
| { | { | ||||
| public: | public: | ||||
| iOSMessageBox (const String& title, const String& message, | |||||
| NSString* button1, NSString* button2, NSString* button3, | |||||
| ModalComponentManager::Callback* cb, const bool async) | |||||
| : result (0), resultReceived (false), callback (cb), isAsync (async) | |||||
| iOSMessageBox (const MessageBoxOptions& opts, std::unique_ptr<ModalComponentManager::Callback>&& cb) | |||||
| : callback (std::move (cb)) | |||||
| { | { | ||||
| if (currentlyFocusedPeer != nullptr) | if (currentlyFocusedPeer != nullptr) | ||||
| { | { | ||||
| UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title) | |||||
| message: juceStringToNS (message) | |||||
| UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (opts.getTitle()) | |||||
| message: juceStringToNS (opts.getMessage()) | |||||
| preferredStyle: UIAlertControllerStyleAlert]; | preferredStyle: UIAlertControllerStyleAlert]; | ||||
| addButton (alert, button1, 0); | |||||
| addButton (alert, button2, 1); | |||||
| addButton (alert, button3, 2); | |||||
| addButton (alert, opts.getButtonText (0)); | |||||
| addButton (alert, opts.getButtonText (1)); | |||||
| addButton (alert, opts.getButtonText (2)); | |||||
| [currentlyFocusedPeer->controller presentViewController: alert | [currentlyFocusedPeer->controller presentViewController: alert | ||||
| animated: YES | animated: YES | ||||
| @@ -469,105 +468,146 @@ public: | |||||
| JUCE_AUTORELEASEPOOL | JUCE_AUTORELEASEPOOL | ||||
| { | { | ||||
| while (! resultReceived) | |||||
| while (result < 0) | |||||
| [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; | [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| void buttonClicked (const int buttonIndex) noexcept | |||||
| void buttonClicked (int buttonIndex) noexcept | |||||
| { | { | ||||
| result = buttonIndex; | |||||
| resultReceived = true; | |||||
| if (callback != nullptr) | if (callback != nullptr) | ||||
| callback->modalStateFinished (result); | |||||
| callback->modalStateFinished (buttonIndex); | |||||
| if (isAsync) | |||||
| delete this; | |||||
| delete this; | |||||
| } | } | ||||
| private: | private: | ||||
| int result; | |||||
| bool resultReceived; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| const bool isAsync; | |||||
| void addButton (UIAlertController* alert, NSString* text, int index) | |||||
| void addButton (UIAlertController* alert, const String& text) | |||||
| { | { | ||||
| if (text != nil) | |||||
| [alert addAction: [UIAlertAction actionWithTitle: text | |||||
| if (! text.isEmpty()) | |||||
| { | |||||
| const auto index = [[alert actions] count]; | |||||
| [alert addAction: [UIAlertAction actionWithTitle: juceStringToNS (text) | |||||
| style: UIAlertActionStyleDefault | style: UIAlertActionStyleDefault | ||||
| handler: ^(UIAlertAction*) { this->buttonClicked (index); }]]; | |||||
| handler: ^(UIAlertAction*) { this->buttonClicked ((int) index); }]]; | |||||
| } | |||||
| } | } | ||||
| int result = -1; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox) | ||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| static int showDialog (const MessageBoxOptions& options, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback, | |||||
| Async async) | |||||
| { | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| if (async == Async::no) | |||||
| { | |||||
| JUCE_AUTORELEASEPOOL | |||||
| { | |||||
| iOSMessageBox messageBox (options, std::move (callback)); | |||||
| return messageBox.getResult(); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| ignoreUnused (async); | |||||
| new iOSMessageBox (options, std::move (callback)); | |||||
| return 0; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/) | Component* /*associatedComponent*/) | ||||
| { | { | ||||
| JUCE_AUTORELEASEPOOL | |||||
| { | |||||
| iOSMessageBox mb (title, message, @"OK", nil, nil, nullptr, false); | |||||
| ignoreUnused (mb.getResult()); | |||||
| } | |||||
| showDialog (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")), | |||||
| nullptr, Async::no); | |||||
| } | |||||
| int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options) | |||||
| { | |||||
| return showDialog (options, nullptr, Async::no); | |||||
| } | } | ||||
| #endif | #endif | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| new iOSMessageBox (title, message, @"OK", nil, nil, callback, true); | |||||
| showDialog (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)), | |||||
| Async::yes); | |||||
| } | } | ||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"OK", | |||||
| nil, callback, callback != nullptr)); | |||||
| if (callback == nullptr) | |||||
| return mb->getResult() == 1; | |||||
| mb.release(); | |||||
| return false; | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no) == 1; | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"Yes", @"No", callback, callback != nullptr)); | |||||
| if (callback == nullptr) | |||||
| return mb->getResult(); | |||||
| mb.release(); | |||||
| return 0; | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType /*iconType*/, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"No", @"Yes", nil, callback, callback != nullptr)); | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | |||||
| if (callback == nullptr) | |||||
| return mb->getResult(); | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | |||||
| showDialog (options, rawToUniquePtr (callback), Async::yes); | |||||
| } | |||||
| mb.release(); | |||||
| return 0; | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -654,16 +654,86 @@ void LookAndFeel::playAlertSound() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static int showDialog (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback, | |||||
| Async async) | |||||
| { | |||||
| const auto dummyCallback = [] (int) {}; | |||||
| switch (options.getNumButtons()) | |||||
| { | |||||
| case 2: | |||||
| { | |||||
| if (async == Async::yes && callback == nullptr) | |||||
| callback = ModalCallbackFunction::create (dummyCallback); | |||||
| return AlertWindow::showOkCancelBox (options.getIconType(), | |||||
| options.getTitle(), | |||||
| options.getMessage(), | |||||
| options.getButtonText (0), | |||||
| options.getButtonText (1), | |||||
| options.getAssociatedComponent(), | |||||
| callback) ? 1 : 0; | |||||
| } | |||||
| case 3: | |||||
| { | |||||
| if (async == Async::yes && callback == nullptr) | |||||
| callback = ModalCallbackFunction::create (dummyCallback); | |||||
| return AlertWindow::showYesNoCancelBox (options.getIconType(), | |||||
| options.getTitle(), | |||||
| options.getMessage(), | |||||
| options.getButtonText (0), | |||||
| options.getButtonText (1), | |||||
| options.getButtonText (2), | |||||
| options.getAssociatedComponent(), | |||||
| callback); | |||||
| } | |||||
| case 1: | |||||
| default: | |||||
| break; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| if (async == Async::no) | |||||
| { | |||||
| AlertWindow::showMessageBox (options.getIconType(), | |||||
| options.getTitle(), | |||||
| options.getMessage(), | |||||
| options.getButtonText (0), | |||||
| options.getAssociatedComponent()); | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (options.getIconType(), | |||||
| options.getTitle(), | |||||
| options.getMessage(), | |||||
| options.getButtonText (0), | |||||
| options.getAssociatedComponent(), | |||||
| callback); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component*) | |||||
| Component* /*associatedComponent*/) | |||||
| { | { | ||||
| AlertWindow::showMessageBox (iconType, title, message); | AlertWindow::showMessageBox (iconType, title, message); | ||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options) | |||||
| { | |||||
| return showDialog (options, nullptr, Async::no); | |||||
| } | |||||
| #endif | #endif | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| @@ -671,7 +741,7 @@ void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIcon | |||||
| AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback); | AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback); | ||||
| } | } | ||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType, | |||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| @@ -679,7 +749,7 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType | |||||
| return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback); | return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback); | ||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| @@ -688,15 +758,27 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy | |||||
| associatedComponent, callback); | associatedComponent, callback); | ||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| return AlertWindow::showOkCancelBox (iconType, title, message, TRANS ("Yes"), TRANS ("No"), | |||||
| return AlertWindow::showOkCancelBox (iconType, title, message, TRANS("Yes"), TRANS("No"), | |||||
| associatedComponent, callback); | associatedComponent, callback); | ||||
| } | } | ||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | |||||
| showDialog (options, callback, Async::yes); | |||||
| } | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| Image juce_createIconForFile (const File&) | Image juce_createIconForFile (const File&) | ||||
| { | { | ||||
| @@ -35,47 +35,29 @@ void LookAndFeel::playAlertSound() | |||||
| class OSXMessageBox : private AsyncUpdater | class OSXMessageBox : private AsyncUpdater | ||||
| { | { | ||||
| public: | public: | ||||
| OSXMessageBox (AlertWindow::AlertIconType type, const String& t, const String& m, | |||||
| const char* b1, const char* b2, const char* b3, | |||||
| ModalComponentManager::Callback* c, const bool runAsync) | |||||
| : iconType (type), title (t), message (m), callback (c), | |||||
| button1 (b1), button2 (b2), button3 (b3) | |||||
| OSXMessageBox (const MessageBoxOptions& opts, | |||||
| std::unique_ptr<ModalComponentManager::Callback>&& c) | |||||
| : options (opts), callback (std::move (c)) | |||||
| { | { | ||||
| if (runAsync) | |||||
| triggerAsyncUpdate(); | |||||
| } | } | ||||
| int getResult() const | int getResult() const | ||||
| { | { | ||||
| switch (getRawResult()) | switch (getRawResult()) | ||||
| { | { | ||||
| case NSAlertFirstButtonReturn: return 1; | |||||
| case NSAlertThirdButtonReturn: return 2; | |||||
| default: return 0; | |||||
| case NSAlertFirstButtonReturn: return 0; | |||||
| case NSAlertSecondButtonReturn: return 1; | |||||
| case NSAlertThirdButtonReturn: return 2; | |||||
| default: break; | |||||
| } | } | ||||
| } | |||||
| static int show (AlertWindow::AlertIconType iconType, const String& title, const String& message, | |||||
| ModalComponentManager::Callback* callback, const char* b1, const char* b2, const char* b3, | |||||
| bool runAsync) | |||||
| { | |||||
| std::unique_ptr<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message, b1, b2, b3, | |||||
| callback, runAsync)); | |||||
| if (! runAsync) | |||||
| return mb->getResult(); | |||||
| mb.release(); | |||||
| jassertfalse; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| private: | |||||
| AlertWindow::AlertIconType iconType; | |||||
| String title, message; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| const char* button1; | |||||
| const char* button2; | |||||
| const char* button3; | |||||
| using AsyncUpdater::triggerAsyncUpdate; | |||||
| private: | |||||
| void handleAsyncUpdate() override | void handleAsyncUpdate() override | ||||
| { | { | ||||
| auto result = getResult(); | auto result = getResult(); | ||||
| @@ -86,73 +68,147 @@ private: | |||||
| delete this; | delete this; | ||||
| } | } | ||||
| static void addButton (NSAlert* alert, const String& button) | |||||
| { | |||||
| if (! button.isEmpty()) | |||||
| [alert addButtonWithTitle: juceStringToNS (button)]; | |||||
| } | |||||
| NSInteger getRawResult() const | NSInteger getRawResult() const | ||||
| { | { | ||||
| NSAlert* alert = [[[NSAlert alloc] init] autorelease]; | NSAlert* alert = [[[NSAlert alloc] init] autorelease]; | ||||
| [alert setMessageText: juceStringToNS (title)]; | |||||
| [alert setInformativeText: juceStringToNS (message)]; | |||||
| [alert setMessageText: juceStringToNS (options.getTitle())]; | |||||
| [alert setInformativeText: juceStringToNS (options.getMessage())]; | |||||
| [alert setAlertStyle: options.getIconType() == MessageBoxIconType::WarningIcon ? NSAlertStyleCritical | |||||
| : NSAlertStyleInformational]; | |||||
| [alert setAlertStyle: iconType == AlertWindow::WarningIcon ? NSAlertStyleCritical | |||||
| : NSAlertStyleInformational]; | |||||
| addButton (alert, button1); | |||||
| addButton (alert, button2); | |||||
| addButton (alert, button3); | |||||
| const auto button1Text = options.getButtonText (0); | |||||
| addButton (alert, button1Text.isEmpty() ? "OK" : button1Text); | |||||
| addButton (alert, options.getButtonText (1)); | |||||
| addButton (alert, options.getButtonText (2)); | |||||
| return [alert runModal]; | return [alert runModal]; | ||||
| } | } | ||||
| static void addButton (NSAlert* alert, const char* button) | |||||
| { | |||||
| if (button != nullptr) | |||||
| [alert addButtonWithTitle: juceStringToNS (TRANS (button))]; | |||||
| } | |||||
| MessageBoxOptions options; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXMessageBox) | |||||
| }; | }; | ||||
| static int showDialog (const MessageBoxOptions& options, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback, | |||||
| Async async) | |||||
| { | |||||
| auto messageBox = std::make_unique<OSXMessageBox> (options, std::move (callback)); | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| if (async == Async::no) | |||||
| return messageBox->getResult(); | |||||
| #endif | |||||
| ignoreUnused (async); | |||||
| messageBox->triggerAsyncUpdate(); | |||||
| messageBox.release(); | |||||
| return 0; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/) | Component* /*associatedComponent*/) | ||||
| { | { | ||||
| OSXMessageBox::show (iconType, title, message, nullptr, "OK", nullptr, nullptr, false); | |||||
| showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")), | |||||
| nullptr, | |||||
| Async::no); | |||||
| } | |||||
| int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options) | |||||
| { | |||||
| return showDialog (options, nullptr, Async::no); | |||||
| } | } | ||||
| #endif | #endif | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| OSXMessageBox::show (iconType, title, message, callback, "OK", nullptr, nullptr, true); | |||||
| showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)), | |||||
| Async::yes); | |||||
| } | } | ||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType, | |||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| return OSXMessageBox::show (iconType, title, message, callback, | |||||
| "OK", "Cancel", nullptr, callback != nullptr) == 1; | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no) != 0; | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| return OSXMessageBox::show (iconType, title, message, callback, | |||||
| "Yes", "Cancel", "No", callback != nullptr); | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")) | |||||
| .withButton (TRANS("Cancel")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* /*associatedComponent*/, | Component* /*associatedComponent*/, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| return OSXMessageBox::show (iconType, title, message, callback, | |||||
| "Yes", "No", nullptr, callback != nullptr); | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | } | ||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | |||||
| showDialog (options, rawToUniquePtr (callback), Async::yes); | |||||
| } | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| static NSRect getDragRect (NSView* view, NSEvent* event) | static NSRect getDragRect (NSView* view, NSEvent* event) | ||||
| @@ -4411,30 +4411,44 @@ bool juce_areThereAnyAlwaysOnTopWindows() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| class WindowsMessageBox : public AsyncUpdater | |||||
| #if JUCE_MSVC | |||||
| // required to enable the newer dialog box on vista and above | |||||
| #pragma comment(linker, \ | |||||
| "\"/MANIFESTDEPENDENCY:type='Win32' " \ | |||||
| "name='Microsoft.Windows.Common-Controls' " \ | |||||
| "version='6.0.0.0' " \ | |||||
| "processorArchitecture='*' " \ | |||||
| "publicKeyToken='6595b64144ccf1df' " \ | |||||
| "language='*'\"" \ | |||||
| ) | |||||
| #endif | |||||
| class WindowsMessageBoxBase : private AsyncUpdater | |||||
| { | { | ||||
| public: | public: | ||||
| WindowsMessageBox (AlertWindow::AlertIconType iconType, | |||||
| const String& boxTitle, const String& m, | |||||
| Component* associatedComponent, UINT extraFlags, | |||||
| ModalComponentManager::Callback* cb, const bool runAsync) | |||||
| : flags (extraFlags | getMessageBoxFlags (iconType)), | |||||
| owner (getWindowForMessageBox (associatedComponent)), | |||||
| title (boxTitle), message (m), callback (cb) | |||||
| WindowsMessageBoxBase (Component* comp, | |||||
| std::unique_ptr<ModalComponentManager::Callback>&& cb) | |||||
| : associatedComponent (comp), | |||||
| callback (std::move (cb)) | |||||
| { | { | ||||
| if (runAsync) | |||||
| triggerAsyncUpdate(); | |||||
| } | } | ||||
| int getResult() const | |||||
| virtual int getResult() = 0; | |||||
| HWND getParentHWND() const | |||||
| { | { | ||||
| const int r = MessageBox (owner, message.toWideCharPointer(), title.toWideCharPointer(), flags); | |||||
| return (r == IDYES || r == IDOK) ? 1 : (r == IDNO && (flags & 1) != 0 ? 2 : 0); | |||||
| if (associatedComponent != nullptr) | |||||
| return (HWND) associatedComponent->getWindowHandle(); | |||||
| return nullptr; | |||||
| } | } | ||||
| using AsyncUpdater::triggerAsyncUpdate; | |||||
| private: | |||||
| void handleAsyncUpdate() override | void handleAsyncUpdate() override | ||||
| { | { | ||||
| const int result = getResult(); | |||||
| const auto result = getResult(); | |||||
| if (callback != nullptr) | if (callback != nullptr) | ||||
| callback->modalStateFinished (result); | callback->modalStateFinished (result); | ||||
| @@ -4442,97 +4456,303 @@ public: | |||||
| delete this; | delete this; | ||||
| } | } | ||||
| private: | |||||
| UINT flags; | |||||
| HWND owner; | |||||
| String title, message; | |||||
| Component::SafePointer<Component> associatedComponent; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | std::unique_ptr<ModalComponentManager::Callback> callback; | ||||
| static UINT getMessageBoxFlags (AlertWindow::AlertIconType iconType) noexcept | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsMessageBoxBase) | |||||
| }; | |||||
| class PreVistaMessageBox : public WindowsMessageBoxBase | |||||
| { | |||||
| public: | |||||
| PreVistaMessageBox (const MessageBoxOptions& opts, | |||||
| UINT extraFlags, | |||||
| std::unique_ptr<ModalComponentManager::Callback>&& callback) | |||||
| : WindowsMessageBoxBase (opts.getAssociatedComponent(), std::move (callback)), | |||||
| flags (extraFlags | getMessageBoxFlags (opts.getIconType())), | |||||
| title (opts.getTitle()), message (opts.getMessage()) | |||||
| { | { | ||||
| UINT flags = MB_TASKMODAL | MB_SETFOREGROUND; | |||||
| } | |||||
| int getResult() override | |||||
| { | |||||
| const auto result = MessageBox (getParentHWND(), message.toWideCharPointer(), title.toWideCharPointer(), flags); | |||||
| if (result == IDYES || result == IDOK) return 0; | |||||
| if (result == IDNO && ((flags & 1) != 0)) return 1; | |||||
| return 2; | |||||
| } | |||||
| private: | |||||
| static UINT getMessageBoxFlags (MessageBoxIconType iconType) noexcept | |||||
| { | |||||
| // this window can get lost behind JUCE windows which are set to be alwaysOnTop | // this window can get lost behind JUCE windows which are set to be alwaysOnTop | ||||
| // so if there are any set it to be topmost | // so if there are any set it to be topmost | ||||
| if (juce_areThereAnyAlwaysOnTopWindows()) | |||||
| flags |= MB_TOPMOST; | |||||
| const auto topmostFlag = juce_areThereAnyAlwaysOnTopWindows() ? MB_TOPMOST : 0; | |||||
| switch (iconType) | |||||
| const auto iconFlags = [&]() -> decltype (topmostFlag) | |||||
| { | { | ||||
| case AlertWindow::QuestionIcon: flags |= MB_ICONQUESTION; break; | |||||
| case AlertWindow::WarningIcon: flags |= MB_ICONWARNING; break; | |||||
| case AlertWindow::InfoIcon: flags |= MB_ICONINFORMATION; break; | |||||
| case AlertWindow::NoIcon: JUCE_FALLTHROUGH | |||||
| default: break; | |||||
| switch (iconType) | |||||
| { | |||||
| case MessageBoxIconType::QuestionIcon: return MB_ICONQUESTION; | |||||
| case MessageBoxIconType::WarningIcon: return MB_ICONWARNING; | |||||
| case MessageBoxIconType::InfoIcon: return MB_ICONINFORMATION; | |||||
| case MessageBoxIconType::NoIcon: break; | |||||
| } | |||||
| return 0; | |||||
| }(); | |||||
| return static_cast<UINT> (MB_TASKMODAL | MB_SETFOREGROUND | topmostFlag | iconFlags); | |||||
| } | |||||
| const UINT flags; | |||||
| const String title, message; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreVistaMessageBox) | |||||
| }; | |||||
| using TaskDialogIndirectFunc = HRESULT (WINAPI*) (const TASKDIALOGCONFIG*, INT*, INT*, BOOL*); | |||||
| static TaskDialogIndirectFunc taskDialogIndirect = nullptr; | |||||
| class WindowsTaskDialog : public WindowsMessageBoxBase | |||||
| { | |||||
| public: | |||||
| WindowsTaskDialog (const MessageBoxOptions& opts, | |||||
| std::unique_ptr<ModalComponentManager::Callback>&& callback) | |||||
| : WindowsMessageBoxBase (opts.getAssociatedComponent(), std::move (callback)), | |||||
| iconType (opts.getIconType()), | |||||
| title (opts.getTitle()), message (opts.getMessage()), | |||||
| button1 (opts.getButtonText (0)), button2 (opts.getButtonText (1)), button3 (opts.getButtonText (2)) | |||||
| { | |||||
| } | |||||
| int getResult() override | |||||
| { | |||||
| TASKDIALOGCONFIG config = { 0 }; | |||||
| config.cbSize = sizeof (config); | |||||
| config.pszWindowTitle = title.toWideCharPointer(); | |||||
| config.pszContent = message.toWideCharPointer(); | |||||
| config.hInstance = (HINSTANCE) Process::getCurrentModuleInstanceHandle(); | |||||
| if (iconType == MessageBoxIconType::QuestionIcon) | |||||
| { | |||||
| if (auto* questionIcon = LoadIcon (nullptr, IDI_QUESTION)) | |||||
| { | |||||
| config.hMainIcon = questionIcon; | |||||
| config.dwFlags |= TDF_USE_HICON_MAIN; | |||||
| } | |||||
| } | } | ||||
| else | |||||
| { | |||||
| auto icon = [this]() -> LPWSTR | |||||
| { | |||||
| switch (iconType) | |||||
| { | |||||
| case MessageBoxIconType::WarningIcon: return TD_WARNING_ICON; | |||||
| case MessageBoxIconType::InfoIcon: return TD_INFORMATION_ICON; | |||||
| case MessageBoxIconType::QuestionIcon: JUCE_FALLTHROUGH | |||||
| case MessageBoxIconType::NoIcon: | |||||
| break; | |||||
| } | |||||
| return nullptr; | |||||
| }(); | |||||
| return flags; | |||||
| if (icon != nullptr) | |||||
| config.pszMainIcon = icon; | |||||
| } | |||||
| std::vector<TASKDIALOG_BUTTON> buttons; | |||||
| for (const auto* buttonText : { &button1, &button2, &button3 }) | |||||
| if (buttonText->isNotEmpty()) | |||||
| buttons.push_back ({ (int) buttons.size(), buttonText->toWideCharPointer() }); | |||||
| config.pButtons = buttons.data(); | |||||
| config.cButtons = (UINT) buttons.size(); | |||||
| int buttonIndex = 0; | |||||
| taskDialogIndirect (&config, &buttonIndex, nullptr, nullptr); | |||||
| return buttonIndex; | |||||
| } | } | ||||
| static HWND getWindowForMessageBox (Component* associatedComponent) | |||||
| static bool loadTaskDialog() | |||||
| { | { | ||||
| return associatedComponent != nullptr ? (HWND) associatedComponent->getWindowHandle() : nullptr; | |||||
| static bool hasChecked = false; | |||||
| if (! hasChecked) | |||||
| { | |||||
| hasChecked = true; | |||||
| const auto comctl = "Comctl32.dll"; | |||||
| LoadLibraryA (comctl); | |||||
| const auto comctlModule = GetModuleHandleA (comctl); | |||||
| if (comctlModule != nullptr) | |||||
| taskDialogIndirect = (TaskDialogIndirectFunc) GetProcAddress (comctlModule, "TaskDialogIndirect"); | |||||
| } | |||||
| return taskDialogIndirect != nullptr; | |||||
| } | } | ||||
| private: | |||||
| MessageBoxIconType iconType; | |||||
| String title, message, button1, button2, button3; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTaskDialog) | |||||
| }; | }; | ||||
| static std::unique_ptr<WindowsMessageBoxBase> createMessageBox (const MessageBoxOptions& options, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback) | |||||
| { | |||||
| std::unique_ptr<WindowsMessageBoxBase> messageBox; | |||||
| if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista | |||||
| && WindowsTaskDialog::loadTaskDialog()) | |||||
| { | |||||
| messageBox.reset (new WindowsTaskDialog (options, std::move (callback))); | |||||
| } | |||||
| else | |||||
| { | |||||
| const auto extraFlags = [&options] | |||||
| { | |||||
| const auto numButtons = options.getNumButtons(); | |||||
| if (numButtons == 3) | |||||
| return MB_YESNOCANCEL; | |||||
| if (numButtons == 2) | |||||
| return options.getButtonText (0) == "OK" ? MB_OKCANCEL | |||||
| : MB_YESNO; | |||||
| return MB_OK; | |||||
| }(); | |||||
| messageBox.reset (new PreVistaMessageBox (options, (UINT) extraFlags, std::move (callback))); | |||||
| } | |||||
| return messageBox; | |||||
| } | |||||
| static int showDialog (const MessageBoxOptions& options, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback, | |||||
| Async async) | |||||
| { | |||||
| auto messageBox = createMessageBox (options, std::move (callback)); | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| if (async == Async::no) | |||||
| return messageBox->getResult(); | |||||
| #endif | |||||
| ignoreUnused (async); | |||||
| messageBox->triggerAsyncUpdate(); | |||||
| messageBox.release(); | |||||
| return 0; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent) | Component* associatedComponent) | ||||
| { | { | ||||
| WindowsMessageBox box (iconType, title, message, associatedComponent, MB_OK, nullptr, false); | |||||
| (void) box.getResult(); | |||||
| showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| nullptr, | |||||
| Async::no); | |||||
| } | |||||
| int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options) | |||||
| { | |||||
| return showDialog (options, nullptr, Async::no); | |||||
| } | } | ||||
| #endif | #endif | ||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType, | |||||
| void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| new WindowsMessageBox (iconType, title, message, associatedComponent, MB_OK, callback, true); | |||||
| showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)), | |||||
| Async::yes); | |||||
| } | } | ||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType, | |||||
| bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent, | |||||
| MB_OKCANCEL, callback, callback != nullptr)); | |||||
| if (callback == nullptr) | |||||
| return mb->getResult() != 0; | |||||
| mb.release(); | |||||
| return false; | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("OK")) | |||||
| .withButton (TRANS("Cancel")) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no) == 1; | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent, | |||||
| MB_YESNOCANCEL, callback, callback != nullptr)); | |||||
| if (callback == nullptr) | |||||
| return mb->getResult(); | |||||
| mb.release(); | |||||
| return 0; | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")) | |||||
| .withButton (TRANS("Cancel")) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | } | ||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType, | |||||
| int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType, | |||||
| const String& title, const String& message, | const String& title, const String& message, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| std::unique_ptr<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent, | |||||
| MB_YESNO, callback, callback != nullptr)); | |||||
| if (callback == nullptr) | |||||
| return mb->getResult(); | |||||
| return showDialog (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (TRANS("Yes")) | |||||
| .withButton (TRANS("No")) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)), | |||||
| callback != nullptr ? Async::yes : Async::no); | |||||
| } | |||||
| mb.release(); | |||||
| return 0; | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback) | |||||
| { | |||||
| showDialog (options, rawToUniquePtr (callback), Async::yes); | |||||
| } | |||||
| void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -38,7 +38,7 @@ static juce_wchar getDefaultPasswordChar() noexcept | |||||
| //============================================================================== | //============================================================================== | ||||
| AlertWindow::AlertWindow (const String& title, | AlertWindow::AlertWindow (const String& title, | ||||
| const String& message, | const String& message, | ||||
| AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| Component* comp) | Component* comp) | ||||
| : TopLevelWindow (title, true), | : TopLevelWindow (title, true), | ||||
| alertIconType (iconType), | alertIconType (iconType), | ||||
| @@ -561,20 +561,21 @@ int AlertWindow::getDesktopWindowStyleFlags() const | |||||
| return getLookAndFeel().getAlertBoxWindowFlags(); | return getLookAndFeel().getAlertBoxWindowFlags(); | ||||
| } | } | ||||
| enum class Async { no, yes }; | |||||
| //============================================================================== | //============================================================================== | ||||
| class AlertWindowInfo | class AlertWindowInfo | ||||
| { | { | ||||
| public: | public: | ||||
| AlertWindowInfo (const String& t, const String& m, Component* component, | |||||
| AlertWindow::AlertIconType icon, int numButts, | |||||
| ModalComponentManager::Callback* cb, bool runModally) | |||||
| : title (t), message (m), iconType (icon), numButtons (numButts), | |||||
| associatedComponent (component), callback (cb), modal (runModally) | |||||
| AlertWindowInfo (const MessageBoxOptions& opts, | |||||
| std::unique_ptr<ModalComponentManager::Callback>&& cb, | |||||
| Async showAsync) | |||||
| : options (opts), | |||||
| callback (std::move (cb)), | |||||
| async (showAsync) | |||||
| { | { | ||||
| } | } | ||||
| String title, message, button1, button2, button3; | |||||
| int invoke() const | int invoke() const | ||||
| { | { | ||||
| MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this); | MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this); | ||||
| @@ -582,88 +583,153 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| AlertWindow::AlertIconType iconType; | |||||
| int numButtons, returnValue = 0; | |||||
| WeakReference<Component> associatedComponent; | |||||
| ModalComponentManager::Callback* callback; | |||||
| bool modal; | |||||
| static void* showCallback (void* userData) | |||||
| { | |||||
| static_cast<AlertWindowInfo*> (userData)->show(); | |||||
| return nullptr; | |||||
| } | |||||
| void show() | void show() | ||||
| { | { | ||||
| auto& lf = associatedComponent != nullptr ? associatedComponent->getLookAndFeel() | |||||
| : LookAndFeel::getDefaultLookAndFeel(); | |||||
| auto* component = options.getAssociatedComponent(); | |||||
| auto& lf = (component != nullptr ? component->getLookAndFeel() | |||||
| : LookAndFeel::getDefaultLookAndFeel()); | |||||
| std::unique_ptr<AlertWindow> alertBox (lf.createAlertWindow (title, message, button1, button2, button3, | |||||
| iconType, numButtons, associatedComponent)); | |||||
| std::unique_ptr<AlertWindow> alertBox (lf.createAlertWindow (options.getTitle(), options.getMessage(), | |||||
| options.getButtonText (0), options.getButtonText (1), options.getButtonText (2), | |||||
| options.getIconType(), options.getNumButtons(), component)); | |||||
| jassert (alertBox != nullptr); // you have to return one of these! | jassert (alertBox != nullptr); // you have to return one of these! | ||||
| alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows()); | alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows()); | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| if (modal) | |||||
| { | |||||
| if (async == Async::no) | |||||
| returnValue = alertBox->runModalLoop(); | returnValue = alertBox->runModalLoop(); | ||||
| } | |||||
| else | else | ||||
| #endif | #endif | ||||
| { | { | ||||
| ignoreUnused (modal); | |||||
| ignoreUnused (async); | |||||
| alertBox->enterModalState (true, callback, true); | |||||
| alertBox->enterModalState (true, callback.release(), true); | |||||
| alertBox.release(); | alertBox.release(); | ||||
| } | } | ||||
| } | } | ||||
| static void* showCallback (void* userData) | |||||
| MessageBoxOptions options; | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback; | |||||
| const Async async; | |||||
| int returnValue = 0; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindowInfo) | |||||
| }; | |||||
| namespace AlertWindowMappings | |||||
| { | |||||
| static int messageBox (int) { return 0; } | |||||
| static int okCancel (int buttonIndex) { return buttonIndex == 0 ? 1 : 0; } | |||||
| static int yesNoCancel (int buttonIndex) { return buttonIndex == 2 ? 0 : buttonIndex + 1; } | |||||
| ModalComponentManager::Callback* getWrappedCallback (ModalComponentManager::Callback* callbackIn, | |||||
| std::function<int (int)> mapFn) | |||||
| { | { | ||||
| static_cast<AlertWindowInfo*> (userData)->show(); | |||||
| return nullptr; | |||||
| if (callbackIn == nullptr) | |||||
| return nullptr; | |||||
| auto wrappedCallback = [innerCallback = rawToUniquePtr (callbackIn), mapFn] (int buttonIndex) | |||||
| { | |||||
| innerCallback->modalStateFinished (mapFn (buttonIndex)); | |||||
| }; | |||||
| return ModalCallbackFunction::create (std::move (wrappedCallback)); | |||||
| } | } | ||||
| }; | |||||
| } | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| void AlertWindow::showMessageBox (AlertIconType iconType, | |||||
| void AlertWindow::showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& buttonText, | const String& buttonText, | ||||
| Component* associatedComponent) | Component* associatedComponent) | ||||
| { | |||||
| show (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText) | |||||
| .withAssociatedComponent (associatedComponent)); | |||||
| } | |||||
| int AlertWindow::show (const MessageBoxOptions& options) | |||||
| { | |||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | |||||
| return NativeMessageBox::show (options); | |||||
| AlertWindowInfo info (options, nullptr, Async::no); | |||||
| return info.invoke(); | |||||
| } | |||||
| #endif | |||||
| void AlertWindow::showAsync (const MessageBoxOptions& options, ModalComponentManager::Callback* callback) | |||||
| { | { | ||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | ||||
| { | { | ||||
| NativeMessageBox::showMessageBox (iconType, title, message, associatedComponent); | |||||
| NativeMessageBox::showAsync (options, callback); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| AlertWindowInfo info (title, message, associatedComponent, iconType, 1, nullptr, true); | |||||
| info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText; | |||||
| AlertWindowInfo info (options, rawToUniquePtr (callback), Async::yes); | |||||
| info.invoke(); | info.invoke(); | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| void AlertWindow::showMessageBoxAsync (AlertIconType iconType, | |||||
| void AlertWindow::showAsync (const MessageBoxOptions& options, std::function<void (int)> callback) | |||||
| { | |||||
| showAsync (options, ModalCallbackFunction::create (callback)); | |||||
| } | |||||
| void AlertWindow::showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& buttonText, | const String& buttonText, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | |||||
| callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox); | |||||
| showAsync (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| callback); | |||||
| } | |||||
| static int showMaybeAsync (const MessageBoxOptions& options, | |||||
| std::unique_ptr<ModalComponentManager::Callback> callback) | |||||
| { | |||||
| const auto showAsync = (callback != nullptr ? Async::yes | |||||
| : Async::no); | |||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | ||||
| { | { | ||||
| NativeMessageBox::showMessageBoxAsync (iconType, title, message, associatedComponent, callback); | |||||
| } | |||||
| else | |||||
| { | |||||
| AlertWindowInfo info (title, message, associatedComponent, iconType, 1, callback, false); | |||||
| info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText; | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| if (showAsync == Async::no) | |||||
| return NativeMessageBox::show (options); | |||||
| #endif | |||||
| info.invoke(); | |||||
| NativeMessageBox::showAsync (options, callback.release()); | |||||
| return false; | |||||
| } | } | ||||
| AlertWindowInfo info (options, std::move (callback), showAsync); | |||||
| return info.invoke(); | |||||
| } | } | ||||
| bool AlertWindow::showOkCancelBox (AlertIconType iconType, | |||||
| bool AlertWindow::showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& button1Text, | const String& button1Text, | ||||
| @@ -672,16 +738,19 @@ bool AlertWindow::showOkCancelBox (AlertIconType iconType, | |||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | ||||
| return NativeMessageBox::showOkCancelBox (iconType, title, message, associatedComponent, callback); | |||||
| AlertWindowInfo info (title, message, associatedComponent, iconType, 2, callback, callback == nullptr); | |||||
| info.button1 = button1Text.isEmpty() ? TRANS("OK") : button1Text; | |||||
| info.button2 = button2Text.isEmpty() ? TRANS("Cancel") : button2Text; | |||||
| callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel); | |||||
| return info.invoke() != 0; | |||||
| return showMaybeAsync (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (button1Text.isEmpty() ? TRANS("OK") : button1Text) | |||||
| .withButton (button2Text.isEmpty() ? TRANS("Cancel") : button2Text) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (callback)) == 1; | |||||
| } | } | ||||
| int AlertWindow::showYesNoCancelBox (AlertIconType iconType, | |||||
| int AlertWindow::showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& button1Text, | const String& button1Text, | ||||
| @@ -691,29 +760,19 @@ int AlertWindow::showYesNoCancelBox (AlertIconType iconType, | |||||
| ModalComponentManager::Callback* callback) | ModalComponentManager::Callback* callback) | ||||
| { | { | ||||
| if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()) | ||||
| return NativeMessageBox::showYesNoCancelBox (iconType, title, message, associatedComponent, callback); | |||||
| AlertWindowInfo info (title, message, associatedComponent, iconType, 3, callback, callback == nullptr); | |||||
| info.button1 = button1Text.isEmpty() ? TRANS("Yes") : button1Text; | |||||
| info.button2 = button2Text.isEmpty() ? TRANS("No") : button2Text; | |||||
| info.button3 = button3Text.isEmpty() ? TRANS("Cancel") : button3Text; | |||||
| return info.invoke(); | |||||
| callback = AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel); | |||||
| return showMaybeAsync (MessageBoxOptions() | |||||
| .withIconType (iconType) | |||||
| .withTitle (title) | |||||
| .withMessage (message) | |||||
| .withButton (button1Text.isEmpty() ? TRANS("Yes") : button1Text) | |||||
| .withButton (button2Text.isEmpty() ? TRANS("No") : button2Text) | |||||
| .withButton (button3Text.isEmpty() ? TRANS("Cancel") : button3Text) | |||||
| .withAssociatedComponent (associatedComponent), | |||||
| rawToUniquePtr (callback)); | |||||
| } | } | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| bool AlertWindow::showNativeDialogBox (const String& title, | |||||
| const String& bodyText, | |||||
| bool isOkCancel) | |||||
| { | |||||
| if (isOkCancel) | |||||
| return NativeMessageBox::showOkCancelBox (AlertWindow::NoIcon, title, bodyText); | |||||
| NativeMessageBox::showMessageBox (AlertWindow::NoIcon, title, bodyText); | |||||
| return true; | |||||
| } | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| std::unique_ptr<AccessibilityHandler> AlertWindow::createAccessibilityHandler() | std::unique_ptr<AccessibilityHandler> AlertWindow::createAccessibilityHandler() | ||||
| { | { | ||||
| @@ -44,20 +44,6 @@ namespace juce | |||||
| class JUCE_API AlertWindow : public TopLevelWindow | class JUCE_API AlertWindow : public TopLevelWindow | ||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | |||||
| /** The type of icon to show in the dialog box. */ | |||||
| enum AlertIconType | |||||
| { | |||||
| NoIcon, /**< No icon will be shown on the dialog box. */ | |||||
| QuestionIcon, /**< A question-mark icon, for dialog boxes that need the | |||||
| user to answer a question. */ | |||||
| WarningIcon, /**< An exclamation mark to indicate that the dialog is a | |||||
| warning about something and shouldn't be ignored. */ | |||||
| InfoIcon /**< An icon that indicates that the dialog box is just | |||||
| giving the user some information, which doesn't require | |||||
| a response from them. */ | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates an AlertWindow. | /** Creates an AlertWindow. | ||||
| @@ -71,7 +57,7 @@ public: | |||||
| */ | */ | ||||
| AlertWindow (const String& title, | AlertWindow (const String& title, | ||||
| const String& message, | const String& message, | ||||
| AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| Component* associatedComponent = nullptr); | Component* associatedComponent = nullptr); | ||||
| /** Destroys the AlertWindow */ | /** Destroys the AlertWindow */ | ||||
| @@ -80,7 +66,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the type of alert icon that was specified when the window | /** Returns the type of alert icon that was specified when the window | ||||
| was created. */ | was created. */ | ||||
| AlertIconType getAlertType() const noexcept { return alertIconType; } | |||||
| MessageBoxIconType getAlertType() const noexcept { return alertIconType; } | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Changes the dialog box's message. | /** Changes the dialog box's message. | ||||
| @@ -226,8 +212,6 @@ public: | |||||
| bool containsAnyExtraComponents() const; | bool containsAnyExtraComponents() const; | ||||
| //============================================================================== | //============================================================================== | ||||
| // easy-to-use message box functions: | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| /** Shows a dialog box that just has a message and a single button to get rid of it. | /** Shows a dialog box that just has a message and a single button to get rid of it. | ||||
| @@ -244,13 +228,57 @@ public: | |||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| */ | */ | ||||
| static void JUCE_CALLTYPE showMessageBox (AlertIconType iconType, | |||||
| static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& buttonText = String(), | const String& buttonText = String(), | ||||
| Component* associatedComponent = nullptr); | Component* associatedComponent = nullptr); | ||||
| /** Shows a dialog box using the specified options. | |||||
| The box is shown modally, and the method will block until the user dismisses it. | |||||
| @param options the options to use when creating the dialog. | |||||
| @returns the index of the button that was clicked. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static int JUCE_CALLTYPE show (const MessageBoxOptions& options); | |||||
| #endif | #endif | ||||
| /** Shows a dialog box using the specified options. | |||||
| The box will be displayed and placed into a modal state, but this method will return | |||||
| immediately, and the callback will be invoked later when the user dismisses the box. | |||||
| @param options the options to use when creating the dialog. | |||||
| @param callback if this is non-null, the callback will receive a call to its | |||||
| modalStateFinished() when the box is dismissed with the index of the | |||||
| button that was clicked as its argument. | |||||
| The callback object will be owned and deleted by the system, so make sure | |||||
| that it works safely and doesn't keep any references to objects that might | |||||
| be deleted before it gets called. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback); | |||||
| /** Shows a dialog box using the specified options. | |||||
| The box will be displayed and placed into a modal state, but this method will return | |||||
| immediately, and the callback will be invoked later when the user dismisses the box. | |||||
| @param options the options to use when creating the dialog. | |||||
| @param callback if this is non-null, the callback will be called when the box is | |||||
| dismissed with the index of the button that was clicked as its argument. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback); | |||||
| /** Shows a dialog box that just has a message and a single button to get rid of it. | /** Shows a dialog box that just has a message and a single button to get rid of it. | ||||
| The box will be displayed and placed into a modal state, but this method will | The box will be displayed and placed into a modal state, but this method will | ||||
| @@ -272,7 +300,7 @@ public: | |||||
| safely and doesn't keep any references to objects that might be deleted | safely and doesn't keep any references to objects that might be deleted | ||||
| before it gets called. | before it gets called. | ||||
| */ | */ | ||||
| static void JUCE_CALLTYPE showMessageBoxAsync (AlertIconType iconType, | |||||
| static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| const String& buttonText = String(), | const String& buttonText = String(), | ||||
| @@ -314,20 +342,20 @@ public: | |||||
| is not null, the method always returns false, and the user's choice is delivered | is not null, the method always returns false, and the user's choice is delivered | ||||
| later by the callback. | later by the callback. | ||||
| */ | */ | ||||
| static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType, | |||||
| static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| const String& button1Text = String(), | const String& button1Text = String(), | ||||
| const String& button2Text = String(), | const String& button2Text = String(), | ||||
| Component* associatedComponent = nullptr, | Component* associatedComponent = nullptr, | ||||
| ModalComponentManager::Callback* callback = nullptr); | ModalComponentManager::Callback* callback = nullptr); | ||||
| #else | |||||
| #else | |||||
| const String& button1Text, | const String& button1Text, | ||||
| const String& button2Text, | const String& button2Text, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback); | ModalComponentManager::Callback* callback); | ||||
| #endif | |||||
| #endif | |||||
| /** Shows a dialog box with three buttons. | /** Shows a dialog box with three buttons. | ||||
| @@ -368,24 +396,27 @@ public: | |||||
| - 1 if the first button was pressed (normally used for 'yes') | - 1 if the first button was pressed (normally used for 'yes') | ||||
| - 2 if the middle button was pressed (normally used for 'no') | - 2 if the middle button was pressed (normally used for 'no') | ||||
| */ | */ | ||||
| static int JUCE_CALLTYPE showYesNoCancelBox (AlertIconType iconType, | |||||
| static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| const String& button1Text = String(), | const String& button1Text = String(), | ||||
| const String& button2Text = String(), | const String& button2Text = String(), | ||||
| const String& button3Text = String(), | const String& button3Text = String(), | ||||
| Component* associatedComponent = nullptr, | Component* associatedComponent = nullptr, | ||||
| ModalComponentManager::Callback* callback = nullptr); | ModalComponentManager::Callback* callback = nullptr); | ||||
| #else | |||||
| #else | |||||
| const String& button1Text, | const String& button1Text, | ||||
| const String& button2Text, | const String& button2Text, | ||||
| const String& button3Text, | const String& button3Text, | ||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback); | ModalComponentManager::Callback* callback); | ||||
| #endif | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| // This has been deprecated, use the NativeMessageBox methods instead for more options. | |||||
| /** Shows an operating-system native dialog box. | /** Shows an operating-system native dialog box. | ||||
| @param title the title to use at the top | @param title the title to use at the top | ||||
| @@ -394,10 +425,9 @@ public: | |||||
| it'll show a box with just an ok button | it'll show a box with just an ok button | ||||
| @returns true if the ok button was pressed, false if they pressed cancel. | @returns true if the ok button was pressed, false if they pressed cancel. | ||||
| */ | */ | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| static bool JUCE_CALLTYPE showNativeDialogBox (const String& title, | |||||
| const String& bodyText, | |||||
| bool isOkCancel); | |||||
| JUCE_DEPRECATED (static bool JUCE_CALLTYPE showNativeDialogBox (const String& title, | |||||
| const String& bodyText, | |||||
| bool isOkCancel)); | |||||
| #endif | #endif | ||||
| @@ -428,7 +458,7 @@ public: | |||||
| const String& button1, | const String& button1, | ||||
| const String& button2, | const String& button2, | ||||
| const String& button3, | const String& button3, | ||||
| AlertWindow::AlertIconType iconType, | |||||
| MessageBoxIconType iconType, | |||||
| int numButtons, | int numButtons, | ||||
| Component* associatedComponent) = 0; | Component* associatedComponent) = 0; | ||||
| @@ -444,6 +474,14 @@ public: | |||||
| virtual Font getAlertWindowFont() = 0; | virtual Font getAlertWindowFont() = 0; | ||||
| }; | }; | ||||
| //============================================================================== | |||||
| using AlertIconType = MessageBoxIconType; | |||||
| static constexpr auto NoIcon = MessageBoxIconType::NoIcon; | |||||
| static constexpr auto QuestionIcon = MessageBoxIconType::QuestionIcon; | |||||
| static constexpr auto WarningIcon = MessageBoxIconType::WarningIcon; | |||||
| static constexpr auto InfoIcon = MessageBoxIconType::InfoIcon; | |||||
| protected: | protected: | ||||
| //============================================================================== | //============================================================================== | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -470,7 +508,7 @@ private: | |||||
| String text; | String text; | ||||
| TextLayout textLayout; | TextLayout textLayout; | ||||
| Label accessibleMessageLabel; | Label accessibleMessageLabel; | ||||
| AlertIconType alertIconType; | |||||
| MessageBoxIconType alertIconType; | |||||
| ComponentBoundsConstrainer constrainer; | ComponentBoundsConstrainer constrainer; | ||||
| ComponentDragger dragger; | ComponentDragger dragger; | ||||
| Rectangle<int> textArea; | Rectangle<int> textArea; | ||||
| @@ -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 | |||||
| @@ -35,33 +35,77 @@ namespace juce | |||||
| class NativeMessageBox | class NativeMessageBox | ||||
| { | { | ||||
| public: | public: | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| /** Shows a dialog box that just has a message and a single 'ok' button to close it. | /** Shows a dialog box that just has a message and a single 'ok' button to close it. | ||||
| The box is shown modally, and the method will block until the user has clicked its | The box is shown modally, and the method will block until the user has clicked its | ||||
| button (or pressed the escape or return keys). | button (or pressed the escape or return keys). | ||||
| @param iconType the type of icon to show | |||||
| @param title the headline to show at the top of the box | |||||
| @param message a longer, more descriptive message to show underneath the title | |||||
| @param iconType the type of icon to show. | |||||
| @param title the headline to show at the top of the box. | |||||
| @param message a longer, more descriptive message to show underneath the title. | |||||
| @param associatedComponent if this is non-null, it specifies the component that the | @param associatedComponent if this is non-null, it specifies the component that the | ||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| */ | */ | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| static void JUCE_CALLTYPE showMessageBox (AlertWindow::AlertIconType iconType, | |||||
| static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| Component* associatedComponent = nullptr); | Component* associatedComponent = nullptr); | ||||
| /** Shows a dialog box using the specified options. | |||||
| The box is shown modally, and the method will block until the user dismisses it. | |||||
| @param options the options to use when creating the dialog. | |||||
| @returns the index of the button that was clicked. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static int JUCE_CALLTYPE show (const MessageBoxOptions& options); | |||||
| #endif | #endif | ||||
| /** Shows a dialog box using the specified options. | |||||
| The box will be displayed and placed into a modal state, but this method will return | |||||
| immediately, and the callback will be invoked later when the user dismisses the box. | |||||
| @param options the options to use when creating the dialog. | |||||
| @param callback if this is non-null, the callback will receive a call to its | |||||
| modalStateFinished() when the box is dismissed with the index of the | |||||
| button that was clicked as its argument. | |||||
| The callback object will be owned and deleted by the system, so make sure | |||||
| that it works safely and doesn't keep any references to objects that might | |||||
| be deleted before it gets called. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options, | |||||
| ModalComponentManager::Callback* callback); | |||||
| /** Shows a dialog box using the specified options. | |||||
| The box will be displayed and placed into a modal state, but this method will return | |||||
| immediately, and the callback will be invoked later when the user dismisses the box. | |||||
| @param options the options to use when creating the dialog. | |||||
| @param callback if this is non-null, the callback will be called when the box is | |||||
| dismissed with the index of the button that was clicked as its argument. | |||||
| @see MessageBoxOptions | |||||
| */ | |||||
| static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options, | |||||
| std::function<void (int)> callback); | |||||
| /** Shows a dialog box that just has a message and a single 'ok' button to close it. | /** Shows a dialog box that just has a message and a single 'ok' button to close it. | ||||
| The box will be displayed and placed into a modal state, but this method will return | The box will be displayed and placed into a modal state, but this method will return | ||||
| immediately, and the callback will be invoked later when the user dismisses the box. | immediately, and the callback will be invoked later when the user dismisses the box. | ||||
| @param iconType the type of icon to show | |||||
| @param title the headline to show at the top of the box | |||||
| @param message a longer, more descriptive message to show underneath the title | |||||
| @param iconType the type of icon to show. | |||||
| @param title the headline to show at the top of the box. | |||||
| @param message a longer, more descriptive message to show underneath the title. | |||||
| @param associatedComponent if this is non-null, it specifies the component that the | @param associatedComponent if this is non-null, it specifies the component that the | ||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| @@ -74,26 +118,26 @@ public: | |||||
| @see ModalCallbackFunction | @see ModalCallbackFunction | ||||
| */ | */ | ||||
| static void JUCE_CALLTYPE showMessageBoxAsync (AlertWindow::AlertIconType iconType, | |||||
| const String& title, | |||||
| const String& message, | |||||
| Component* associatedComponent = nullptr, | |||||
| ModalComponentManager::Callback* callback = nullptr); | |||||
| static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType, | |||||
| const String& title, | |||||
| const String& message, | |||||
| Component* associatedComponent = nullptr, | |||||
| ModalComponentManager::Callback* callback = nullptr); | |||||
| /** Shows a dialog box with two buttons. | /** Shows a dialog box with two buttons. | ||||
| Ideal for ok/cancel or yes/no choices. The return key can also be used | Ideal for ok/cancel or yes/no choices. The return key can also be used | ||||
| to trigger the first button, and the escape key for the second button. | to trigger the first button, and the escape key for the second button. | ||||
| If the callback parameter is null, the box is shown modally, and the method will | |||||
| block until the user has clicked the button (or pressed the escape or return keys). | |||||
| If the callback parameter is non-null, the box will be displayed and placed into a | |||||
| modal state, but this method will return immediately, and the callback will be invoked | |||||
| If the callback parameter is null and modal loops are enabled, the box is shown modally, | |||||
| and the method will block until the user has clicked the button (or pressed the escape or | |||||
| return keys). If the callback parameter is non-null, the box will be displayed and placed | |||||
| into a modal state, but this method will return immediately, and the callback will be invoked | |||||
| later when the user dismisses the box. | later when the user dismisses the box. | ||||
| @param iconType the type of icon to show | |||||
| @param title the headline to show at the top of the box | |||||
| @param message a longer, more descriptive message to show underneath the title | |||||
| @param iconType the type of icon to show. | |||||
| @param title the headline to show at the top of the box. | |||||
| @param message a longer, more descriptive message to show underneath the title. | |||||
| @param associatedComponent if this is non-null, it specifies the component that the | @param associatedComponent if this is non-null, it specifies the component that the | ||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| @@ -111,16 +155,16 @@ public: | |||||
| @see ModalCallbackFunction | @see ModalCallbackFunction | ||||
| */ | */ | ||||
| static bool JUCE_CALLTYPE showOkCancelBox (AlertWindow::AlertIconType iconType, | |||||
| static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| Component* associatedComponent = nullptr, | Component* associatedComponent = nullptr, | ||||
| ModalComponentManager::Callback* callback = nullptr); | ModalComponentManager::Callback* callback = nullptr); | ||||
| #else | |||||
| #else | |||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback); | ModalComponentManager::Callback* callback); | ||||
| #endif | |||||
| #endif | |||||
| /** Shows a dialog box with three buttons. | /** Shows a dialog box with three buttons. | ||||
| @@ -128,15 +172,15 @@ public: | |||||
| The escape key can be used to trigger the third button. | The escape key can be used to trigger the third button. | ||||
| If the callback parameter is null, the box is shown modally, and the method will | |||||
| block until the user has clicked the button (or pressed the escape or return keys). | |||||
| If the callback parameter is non-null, the box will be displayed and placed into a | |||||
| modal state, but this method will return immediately, and the callback will be invoked | |||||
| If the callback parameter is null and modal loops are enabled, the box is shown modally, | |||||
| and the method will block until the user has clicked the button (or pressed the escape or | |||||
| return keys). If the callback parameter is non-null, the box will be displayed and placed | |||||
| into a modal state, but this method will return immediately, and the callback will be invoked | |||||
| later when the user dismisses the box. | later when the user dismisses the box. | ||||
| @param iconType the type of icon to show | |||||
| @param title the headline to show at the top of the box | |||||
| @param message a longer, more descriptive message to show underneath the title | |||||
| @param iconType the type of icon to show. | |||||
| @param title the headline to show at the top of the box. | |||||
| @param message a longer, more descriptive message to show underneath the title. | |||||
| @param associatedComponent if this is non-null, it specifies the component that the | @param associatedComponent if this is non-null, it specifies the component that the | ||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| @@ -157,16 +201,16 @@ public: | |||||
| @see ModalCallbackFunction | @see ModalCallbackFunction | ||||
| */ | */ | ||||
| static int JUCE_CALLTYPE showYesNoCancelBox (AlertWindow::AlertIconType iconType, | |||||
| static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| #if JUCE_MODAL_LOOPS_PERMITTED | |||||
| Component* associatedComponent = nullptr, | Component* associatedComponent = nullptr, | ||||
| ModalComponentManager::Callback* callback = nullptr); | ModalComponentManager::Callback* callback = nullptr); | ||||
| #else | |||||
| #else | |||||
| Component* associatedComponent, | Component* associatedComponent, | ||||
| ModalComponentManager::Callback* callback); | ModalComponentManager::Callback* callback); | ||||
| #endif | |||||
| #endif | |||||
| /** Shows a dialog box with two buttons. | /** Shows a dialog box with two buttons. | ||||
| @@ -174,15 +218,15 @@ public: | |||||
| The escape key can be used to trigger the no button. | The escape key can be used to trigger the no button. | ||||
| If the callback parameter is null, the box is shown modally, and the method will | |||||
| block until the user has clicked the button (or pressed the escape or return keys). | |||||
| If the callback parameter is non-null, the box will be displayed and placed into a | |||||
| modal state, but this method will return immediately, and the callback will be invoked | |||||
| If the callback parameter is null and modal loops are enabled, the box is shown modally, | |||||
| and the method will block until the user has clicked the button (or pressed the escape or | |||||
| return keys). If the callback parameter is non-null, the box will be displayed and placed | |||||
| into a modal state, but this method will return immediately, and the callback will be invoked | |||||
| later when the user dismisses the box. | later when the user dismisses the box. | ||||
| @param iconType the type of icon to show | |||||
| @param title the headline to show at the top of the box | |||||
| @param message a longer, more descriptive message to show underneath the title | |||||
| @param iconType the type of icon to show. | |||||
| @param title the headline to show at the top of the box. | |||||
| @param message a longer, more descriptive message to show underneath the title. | |||||
| @param associatedComponent if this is non-null, it specifies the component that the | @param associatedComponent if this is non-null, it specifies the component that the | ||||
| alert window should be associated with. Depending on the look | alert window should be associated with. Depending on the look | ||||
| and feel, this might be used for positioning of the alert window. | and feel, this might be used for positioning of the alert window. | ||||
| @@ -202,7 +246,7 @@ public: | |||||
| @see ModalCallbackFunction | @see ModalCallbackFunction | ||||
| */ | */ | ||||
| static int JUCE_CALLTYPE showYesNoBox (AlertWindow::AlertIconType iconType, | |||||
| static int JUCE_CALLTYPE showYesNoBox (MessageBoxIconType iconType, | |||||
| const String& title, | const String& title, | ||||
| const String& message, | const String& message, | ||||
| #if JUCE_MODAL_LOOPS_PERMITTED | #if JUCE_MODAL_LOOPS_PERMITTED | ||||
| @@ -41,7 +41,7 @@ ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title, | |||||
| .createAlertWindow (title, {}, | .createAlertWindow (title, {}, | ||||
| cancelButtonText.isEmpty() ? TRANS("Cancel") | cancelButtonText.isEmpty() ? TRANS("Cancel") | ||||
| : cancelButtonText, | : cancelButtonText, | ||||
| {}, {}, AlertWindow::NoIcon, hasCancelButton ? 1 : 0, | |||||
| {}, {}, MessageBoxIconType::NoIcon, hasCancelButton ? 1 : 0, | |||||
| componentToCentreAround)); | componentToCentreAround)); | ||||
| // if there are no buttons, we won't allow the user to interrupt the thread. | // if there are no buttons, we won't allow the user to interrupt the thread. | ||||
| @@ -339,7 +339,7 @@ private: | |||||
| auto result = Result::fail (TRANS ("The file doesn't exist")); | auto result = Result::fail (TRANS ("The file doesn't exist")); | ||||
| if (showMessageOnFailure) | if (showMessageOnFailure) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS ("Failed to open file..."), | TRANS ("Failed to open file..."), | ||||
| TRANS ("There was an error while trying to load the file: FLNM") | TRANS ("There was an error while trying to load the file: FLNM") | ||||
| .replace ("FLNM", "\n" + newFile.getFullPathName()) | .replace ("FLNM", "\n" + newFile.getFullPathName()) | ||||
| @@ -448,7 +448,7 @@ private: | |||||
| callback (parent, alertResult); | callback (parent, alertResult); | ||||
| }); | }); | ||||
| return AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon, | |||||
| return AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon, | |||||
| TRANS ("Closing document..."), | TRANS ("Closing document..."), | ||||
| TRANS ("Do you want to save the changes to \"DCNM\"?") | TRANS ("Do you want to save the changes to \"DCNM\"?") | ||||
| .replace ("DCNM", document.getDocumentTitle()), | .replace ("DCNM", document.getDocumentTitle()), | ||||
| @@ -510,7 +510,7 @@ private: | |||||
| MouseCursor::hideWaitCursor(); | MouseCursor::hideWaitCursor(); | ||||
| if (showMessageOnFailure) | if (showMessageOnFailure) | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS ("Error writing to file..."), | TRANS ("Error writing to file..."), | ||||
| TRANS ("An error occurred while trying to save \"DCNM\" to the file: FLNM") | TRANS ("An error occurred while trying to save \"DCNM\" to the file: FLNM") | ||||
| .replace ("DCNM", parent->document.getDocumentTitle()) | .replace ("DCNM", parent->document.getDocumentTitle()) | ||||
| @@ -682,7 +682,7 @@ private: | |||||
| callback (parent, r == 1); | callback (parent, r == 1); | ||||
| }); | }); | ||||
| return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| return AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| TRANS ("File already exists"), | TRANS ("File already exists"), | ||||
| TRANS ("There's already a file called: FLNM") | TRANS ("There's already a file called: FLNM") | ||||
| .replace ("FLNM", newFile.getFullPathName()) | .replace ("FLNM", newFile.getFullPathName()) | ||||
| @@ -98,7 +98,7 @@ public: | |||||
| KeyEntryWindow (KeyMappingEditorComponent& kec) | KeyEntryWindow (KeyMappingEditorComponent& kec) | ||||
| : AlertWindow (TRANS("New key-mapping"), | : AlertWindow (TRANS("New key-mapping"), | ||||
| TRANS("Please press a key combination now..."), | TRANS("Please press a key combination now..."), | ||||
| AlertWindow::NoIcon), | |||||
| MessageBoxIconType::NoIcon), | |||||
| owner (kec) | owner (kec) | ||||
| { | { | ||||
| addButton (TRANS("OK"), 1); | addButton (TRANS("OK"), 1); | ||||
| @@ -165,7 +165,7 @@ public: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Change key-mapping"), | TRANS("Change key-mapping"), | ||||
| TRANS("This key is already assigned to the command \"CMDN\"") | TRANS("This key is already assigned to the command \"CMDN\"") | ||||
| .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand)) | .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand)) | ||||
| @@ -403,7 +403,7 @@ KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappin | |||||
| resetButton.onClick = [this] | resetButton.onClick = [this] | ||||
| { | { | ||||
| AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, | |||||
| AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon, | |||||
| TRANS("Reset to defaults"), | TRANS("Reset to defaults"), | ||||
| TRANS("Are you sure you want to reset all the key-mappings to their default state?"), | TRANS("Are you sure you want to reset all the key-mappings to their default state?"), | ||||
| TRANS("Reset"), | TRANS("Reset"), | ||||
| @@ -100,13 +100,13 @@ struct OnlineUnlockForm::OverlayComp : public Component, | |||||
| if (result.errorMessage.isNotEmpty()) | if (result.errorMessage.isNotEmpty()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, | |||||
| TRANS("Registration Failed"), | TRANS("Registration Failed"), | ||||
| result.errorMessage); | result.errorMessage); | ||||
| } | } | ||||
| else if (result.informativeMessage.isNotEmpty()) | else if (result.informativeMessage.isNotEmpty()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, | |||||
| TRANS("Registration Complete!"), | TRANS("Registration Complete!"), | ||||
| result.informativeMessage); | result.informativeMessage); | ||||
| } | } | ||||