Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_AlertWindow.cpp 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. static juce_wchar getDefaultPasswordChar() noexcept
  21. {
  22. #if JUCE_LINUX || JUCE_BSD
  23. return 0x2022;
  24. #else
  25. return 0x25cf;
  26. #endif
  27. }
  28. //==============================================================================
  29. AlertWindow::AlertWindow (const String& title,
  30. const String& message,
  31. MessageBoxIconType iconType,
  32. Component* comp)
  33. : TopLevelWindow (title, true),
  34. alertIconType (iconType),
  35. associatedComponent (comp),
  36. desktopScale (comp != nullptr ? Component::getApproximateScaleFactorForComponent (comp) : 1.0f)
  37. {
  38. setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
  39. accessibleMessageLabel.setColour (Label::textColourId, Colours::transparentBlack);
  40. accessibleMessageLabel.setColour (Label::backgroundColourId, Colours::transparentBlack);
  41. accessibleMessageLabel.setColour (Label::outlineColourId, Colours::transparentBlack);
  42. accessibleMessageLabel.setInterceptsMouseClicks (false, false);
  43. addAndMakeVisible (accessibleMessageLabel);
  44. if (message.isEmpty())
  45. text = " "; // to force an update if the message is empty
  46. setMessage (message);
  47. AlertWindow::lookAndFeelChanged();
  48. constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000);
  49. }
  50. AlertWindow::~AlertWindow()
  51. {
  52. // Ensure that the focus does not jump to another TextEditor while we
  53. // remove children.
  54. for (auto* t : textBoxes)
  55. t->setWantsKeyboardFocus (false);
  56. // Give away focus before removing the editors, so that any TextEditor
  57. // with focus has a chance to dismiss native keyboard if shown.
  58. giveAwayKeyboardFocus();
  59. removeAllChildren();
  60. }
  61. void AlertWindow::userTriedToCloseWindow()
  62. {
  63. if (escapeKeyCancels || buttons.size() > 0)
  64. exitModalState (0);
  65. }
  66. //==============================================================================
  67. void AlertWindow::setMessage (const String& message)
  68. {
  69. auto newMessage = message.substring (0, 2048);
  70. if (text != newMessage)
  71. {
  72. text = newMessage;
  73. auto accessibleText = getName() + ". " + text;
  74. accessibleMessageLabel.setText (accessibleText, NotificationType::dontSendNotification);
  75. setDescription (accessibleText);
  76. updateLayout (true);
  77. repaint();
  78. }
  79. }
  80. //==============================================================================
  81. void AlertWindow::exitAlert (Button* button)
  82. {
  83. if (auto* parent = button->getParentComponent())
  84. parent->exitModalState (button->getCommandID());
  85. }
  86. //==============================================================================
  87. void AlertWindow::addButton (const String& name,
  88. const int returnValue,
  89. const KeyPress& shortcutKey1,
  90. const KeyPress& shortcutKey2)
  91. {
  92. auto* b = new TextButton (name, {});
  93. buttons.add (b);
  94. b->setWantsKeyboardFocus (true);
  95. b->setExplicitFocusOrder (1);
  96. b->setMouseClickGrabsKeyboardFocus (false);
  97. b->setCommandToTrigger (nullptr, returnValue, false);
  98. b->addShortcut (shortcutKey1);
  99. b->addShortcut (shortcutKey2);
  100. b->onClick = [this, b] { exitAlert (b); };
  101. Array<TextButton*> buttonsArray (buttons.begin(), buttons.size());
  102. auto& lf = getLookAndFeel();
  103. auto buttonHeight = lf.getAlertWindowButtonHeight();
  104. auto buttonWidths = lf.getWidthsForTextButtons (*this, buttonsArray);
  105. jassert (buttonWidths.size() == buttons.size());
  106. int i = 0;
  107. for (auto* button : buttons)
  108. button->setSize (buttonWidths[i++], buttonHeight);
  109. addAndMakeVisible (b, 0);
  110. updateLayout (false);
  111. }
  112. int AlertWindow::getNumButtons() const
  113. {
  114. return buttons.size();
  115. }
  116. void AlertWindow::triggerButtonClick (const String& buttonName)
  117. {
  118. for (auto* b : buttons)
  119. {
  120. if (buttonName == b->getName())
  121. {
  122. b->triggerClick();
  123. break;
  124. }
  125. }
  126. }
  127. void AlertWindow::setEscapeKeyCancels (bool shouldEscapeKeyCancel)
  128. {
  129. escapeKeyCancels = shouldEscapeKeyCancel;
  130. }
  131. //==============================================================================
  132. void AlertWindow::addTextEditor (const String& name,
  133. const String& initialContents,
  134. const String& onScreenLabel,
  135. const bool isPasswordBox)
  136. {
  137. auto* ed = new TextEditor (name, isPasswordBox ? getDefaultPasswordChar() : 0);
  138. ed->setSelectAllWhenFocused (true);
  139. ed->setEscapeAndReturnKeysConsumed (false);
  140. textBoxes.add (ed);
  141. allComps.add (ed);
  142. ed->setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId));
  143. ed->setFont (getLookAndFeel().getAlertWindowMessageFont());
  144. addAndMakeVisible (ed);
  145. ed->setText (initialContents);
  146. ed->setCaretPosition (initialContents.length());
  147. textboxNames.add (onScreenLabel);
  148. updateLayout (false);
  149. }
  150. TextEditor* AlertWindow::getTextEditor (const String& nameOfTextEditor) const
  151. {
  152. for (auto* tb : textBoxes)
  153. if (tb->getName() == nameOfTextEditor)
  154. return tb;
  155. return nullptr;
  156. }
  157. String AlertWindow::getTextEditorContents (const String& nameOfTextEditor) const
  158. {
  159. if (auto* t = getTextEditor (nameOfTextEditor))
  160. return t->getText();
  161. return {};
  162. }
  163. //==============================================================================
  164. void AlertWindow::addComboBox (const String& name,
  165. const StringArray& items,
  166. const String& onScreenLabel)
  167. {
  168. auto* cb = new ComboBox (name);
  169. comboBoxes.add (cb);
  170. allComps.add (cb);
  171. cb->addItemList (items, 1);
  172. addAndMakeVisible (cb);
  173. cb->setSelectedItemIndex (0);
  174. comboBoxNames.add (onScreenLabel);
  175. updateLayout (false);
  176. }
  177. ComboBox* AlertWindow::getComboBoxComponent (const String& nameOfList) const
  178. {
  179. for (auto* cb : comboBoxes)
  180. if (cb->getName() == nameOfList)
  181. return cb;
  182. return nullptr;
  183. }
  184. //==============================================================================
  185. class AlertTextComp : public TextEditor
  186. {
  187. public:
  188. AlertTextComp (AlertWindow& owner, const String& message, const Font& font)
  189. {
  190. if (owner.isColourSpecified (AlertWindow::textColourId))
  191. setColour (TextEditor::textColourId, owner.findColour (AlertWindow::textColourId));
  192. setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
  193. setColour (TextEditor::outlineColourId, Colours::transparentBlack);
  194. setColour (TextEditor::shadowColourId, Colours::transparentBlack);
  195. setReadOnly (true);
  196. setMultiLine (true, true);
  197. setCaretVisible (false);
  198. setScrollbarsShown (true);
  199. lookAndFeelChanged();
  200. setWantsKeyboardFocus (false);
  201. setFont (font);
  202. setText (message, false);
  203. bestWidth = 2 * (int) std::sqrt (font.getHeight() * (float) font.getStringWidth (message));
  204. }
  205. void updateLayout (const int width)
  206. {
  207. AttributedString s;
  208. s.setJustification (Justification::topLeft);
  209. s.append (getText(), getFont());
  210. TextLayout text;
  211. text.createLayoutWithBalancedLineLengths (s, (float) width - 8.0f);
  212. setSize (width, jmin (width, (int) (text.getHeight() + getFont().getHeight())));
  213. }
  214. int bestWidth;
  215. JUCE_DECLARE_NON_COPYABLE (AlertTextComp)
  216. };
  217. void AlertWindow::addTextBlock (const String& textBlock)
  218. {
  219. auto* c = new AlertTextComp (*this, textBlock, getLookAndFeel().getAlertWindowMessageFont());
  220. textBlocks.add (c);
  221. allComps.add (c);
  222. addAndMakeVisible (c);
  223. updateLayout (false);
  224. }
  225. //==============================================================================
  226. void AlertWindow::addProgressBarComponent (double& progressValue)
  227. {
  228. auto* pb = new ProgressBar (progressValue);
  229. progressBars.add (pb);
  230. allComps.add (pb);
  231. addAndMakeVisible (pb);
  232. updateLayout (false);
  233. }
  234. //==============================================================================
  235. void AlertWindow::addCustomComponent (Component* const component)
  236. {
  237. customComps.add (component);
  238. allComps.add (component);
  239. addAndMakeVisible (component);
  240. updateLayout (false);
  241. }
  242. int AlertWindow::getNumCustomComponents() const { return customComps.size(); }
  243. Component* AlertWindow::getCustomComponent (int index) const { return customComps [index]; }
  244. Component* AlertWindow::removeCustomComponent (const int index)
  245. {
  246. auto* c = getCustomComponent (index);
  247. if (c != nullptr)
  248. {
  249. customComps.removeFirstMatchingValue (c);
  250. allComps.removeFirstMatchingValue (c);
  251. removeChildComponent (c);
  252. updateLayout (false);
  253. }
  254. return c;
  255. }
  256. //==============================================================================
  257. void AlertWindow::paint (Graphics& g)
  258. {
  259. auto& lf = getLookAndFeel();
  260. lf.drawAlertBox (g, *this, textArea, textLayout);
  261. g.setColour (findColour (textColourId));
  262. g.setFont (lf.getAlertWindowFont());
  263. for (int i = textBoxes.size(); --i >= 0;)
  264. {
  265. auto* te = textBoxes.getUnchecked(i);
  266. g.drawFittedText (textboxNames[i],
  267. te->getX(), te->getY() - 14,
  268. te->getWidth(), 14,
  269. Justification::centredLeft, 1);
  270. }
  271. for (int i = comboBoxNames.size(); --i >= 0;)
  272. {
  273. auto* cb = comboBoxes.getUnchecked(i);
  274. g.drawFittedText (comboBoxNames[i],
  275. cb->getX(), cb->getY() - 14,
  276. cb->getWidth(), 14,
  277. Justification::centredLeft, 1);
  278. }
  279. for (auto* c : customComps)
  280. g.drawFittedText (c->getName(),
  281. c->getX(), c->getY() - 14,
  282. c->getWidth(), 14,
  283. Justification::centredLeft, 1);
  284. }
  285. void AlertWindow::updateLayout (const bool onlyIncreaseSize)
  286. {
  287. const int titleH = 24;
  288. const int iconWidth = 80;
  289. auto& lf = getLookAndFeel();
  290. auto messageFont (lf.getAlertWindowMessageFont());
  291. auto wid = jmax (messageFont.getStringWidth (text),
  292. messageFont.getStringWidth (getName()));
  293. auto sw = (int) std::sqrt (messageFont.getHeight() * (float) wid);
  294. auto w = jmin (300 + sw * 2, (int) ((float) getParentWidth() * 0.7f));
  295. const int edgeGap = 10;
  296. const int labelHeight = 18;
  297. int iconSpace = 0;
  298. AttributedString attributedText;
  299. attributedText.append (getName(), lf.getAlertWindowTitleFont());
  300. if (text.isNotEmpty())
  301. attributedText.append ("\n\n" + text, messageFont);
  302. attributedText.setColour (findColour (textColourId));
  303. if (alertIconType == NoIcon)
  304. {
  305. attributedText.setJustification (Justification::centredTop);
  306. textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
  307. }
  308. else
  309. {
  310. attributedText.setJustification (Justification::topLeft);
  311. textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
  312. iconSpace = iconWidth;
  313. }
  314. w = jmax (350, (int) textLayout.getWidth() + iconSpace + edgeGap * 4);
  315. w = jmin (w, (int) ((float) getParentWidth() * 0.7f));
  316. auto textLayoutH = (int) textLayout.getHeight();
  317. auto textBottom = 16 + titleH + textLayoutH;
  318. int h = textBottom;
  319. int buttonW = 40;
  320. for (auto* b : buttons)
  321. buttonW += 16 + b->getWidth();
  322. w = jmax (buttonW, w);
  323. h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;
  324. if (auto* b = buttons[0])
  325. h += 20 + b->getHeight();
  326. for (auto* c : customComps)
  327. {
  328. w = jmax (w, (c->getWidth() * 100) / 80);
  329. h += 10 + c->getHeight();
  330. if (c->getName().isNotEmpty())
  331. h += labelHeight;
  332. }
  333. for (auto* tb : textBlocks)
  334. w = jmax (w, static_cast<const AlertTextComp*> (tb)->bestWidth);
  335. w = jmin (w, (int) ((float) getParentWidth() * 0.7f));
  336. for (auto* tb : textBlocks)
  337. {
  338. auto* ac = static_cast<AlertTextComp*> (tb);
  339. ac->updateLayout ((int) ((float) w * 0.8f));
  340. h += ac->getHeight() + 10;
  341. }
  342. h = jmin (getParentHeight() - 50, h);
  343. if (onlyIncreaseSize)
  344. {
  345. w = jmax (w, getWidth());
  346. h = jmax (h, getHeight());
  347. }
  348. if (! isVisible())
  349. centreAroundComponent (associatedComponent, w, h);
  350. else
  351. setBounds (getBounds().withSizeKeepingCentre (w, h));
  352. textArea.setBounds (edgeGap, edgeGap, w - (edgeGap * 2), h - edgeGap);
  353. accessibleMessageLabel.setBounds (textArea);
  354. const int spacer = 16;
  355. int totalWidth = -spacer;
  356. for (auto* b : buttons)
  357. totalWidth += b->getWidth() + spacer;
  358. auto x = (w - totalWidth) / 2;
  359. auto y = (int) ((float) getHeight() * 0.95f);
  360. for (auto* c : buttons)
  361. {
  362. int ny = proportionOfHeight (0.95f) - c->getHeight();
  363. c->setTopLeftPosition (x, ny);
  364. if (ny < y)
  365. y = ny;
  366. x += c->getWidth() + spacer;
  367. c->toFront (false);
  368. }
  369. y = textBottom;
  370. for (auto* c : allComps)
  371. {
  372. h = 22;
  373. const int comboIndex = comboBoxes.indexOf (dynamic_cast<ComboBox*> (c));
  374. if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
  375. y += labelHeight;
  376. const int tbIndex = textBoxes.indexOf (dynamic_cast<TextEditor*> (c));
  377. if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
  378. y += labelHeight;
  379. if (customComps.contains (c))
  380. {
  381. if (c->getName().isNotEmpty())
  382. y += labelHeight;
  383. c->setTopLeftPosition (proportionOfWidth (0.1f), y);
  384. h = c->getHeight();
  385. }
  386. else if (textBlocks.contains (c))
  387. {
  388. c->setTopLeftPosition ((getWidth() - c->getWidth()) / 2, y);
  389. h = c->getHeight();
  390. }
  391. else
  392. {
  393. c->setBounds (proportionOfWidth (0.1f), y, proportionOfWidth (0.8f), h);
  394. }
  395. y += h + 10;
  396. }
  397. setWantsKeyboardFocus (getNumChildComponents() == 0);
  398. }
  399. bool AlertWindow::containsAnyExtraComponents() const
  400. {
  401. return allComps.size() > 0;
  402. }
  403. //==============================================================================
  404. void AlertWindow::mouseDown (const MouseEvent& e)
  405. {
  406. dragger.startDraggingComponent (this, e);
  407. }
  408. void AlertWindow::mouseDrag (const MouseEvent& e)
  409. {
  410. dragger.dragComponent (this, e, &constrainer);
  411. }
  412. bool AlertWindow::keyPressed (const KeyPress& key)
  413. {
  414. for (auto* b : buttons)
  415. {
  416. if (b->isRegisteredForShortcut (key))
  417. {
  418. b->triggerClick();
  419. return true;
  420. }
  421. }
  422. if (key.isKeyCode (KeyPress::escapeKey) && escapeKeyCancels)
  423. {
  424. exitModalState (0);
  425. return true;
  426. }
  427. if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
  428. {
  429. buttons.getUnchecked(0)->triggerClick();
  430. return true;
  431. }
  432. return false;
  433. }
  434. void AlertWindow::lookAndFeelChanged()
  435. {
  436. const int newFlags = getLookAndFeel().getAlertBoxWindowFlags();
  437. setUsingNativeTitleBar ((newFlags & ComponentPeer::windowHasTitleBar) != 0);
  438. setDropShadowEnabled (isOpaque() && (newFlags & ComponentPeer::windowHasDropShadow) != 0);
  439. updateLayout (false);
  440. }
  441. int AlertWindow::getDesktopWindowStyleFlags() const
  442. {
  443. return getLookAndFeel().getAlertBoxWindowFlags();
  444. }
  445. enum class Async { no, yes };
  446. //==============================================================================
  447. class AlertWindowInfo
  448. {
  449. public:
  450. AlertWindowInfo (const MessageBoxOptions& opts,
  451. std::unique_ptr<ModalComponentManager::Callback>&& cb,
  452. Async showAsync)
  453. : options (opts),
  454. callback (std::move (cb)),
  455. async (showAsync)
  456. {
  457. }
  458. int invoke() const
  459. {
  460. MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
  461. return returnValue;
  462. }
  463. private:
  464. static void* showCallback (void* userData)
  465. {
  466. static_cast<AlertWindowInfo*> (userData)->show();
  467. return nullptr;
  468. }
  469. void show()
  470. {
  471. auto* component = options.getAssociatedComponent();
  472. auto& lf = (component != nullptr ? component->getLookAndFeel()
  473. : LookAndFeel::getDefaultLookAndFeel());
  474. std::unique_ptr<AlertWindow> alertBox (lf.createAlertWindow (options.getTitle(), options.getMessage(),
  475. options.getButtonText (0), options.getButtonText (1), options.getButtonText (2),
  476. options.getIconType(), options.getNumButtons(), component));
  477. jassert (alertBox != nullptr); // you have to return one of these!
  478. alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
  479. #if JUCE_MODAL_LOOPS_PERMITTED
  480. if (async == Async::no)
  481. returnValue = alertBox->runModalLoop();
  482. else
  483. #endif
  484. {
  485. ignoreUnused (async);
  486. alertBox->enterModalState (true, callback.release(), true);
  487. alertBox.release();
  488. }
  489. }
  490. MessageBoxOptions options;
  491. std::unique_ptr<ModalComponentManager::Callback> callback;
  492. const Async async;
  493. int returnValue = 0;
  494. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindowInfo)
  495. };
  496. namespace AlertWindowMappings
  497. {
  498. using MapFn = int (*) (int);
  499. static inline int noMapping (int buttonIndex) { return buttonIndex; }
  500. static inline int messageBox (int) { return 0; }
  501. static inline int okCancel (int buttonIndex) { return buttonIndex == 0 ? 1 : 0; }
  502. static inline int yesNoCancel (int buttonIndex) { return buttonIndex == 2 ? 0 : buttonIndex + 1; }
  503. static std::unique_ptr<ModalComponentManager::Callback> getWrappedCallback (ModalComponentManager::Callback* callbackIn,
  504. MapFn mapFn)
  505. {
  506. jassert (mapFn != nullptr);
  507. if (callbackIn == nullptr)
  508. return nullptr;
  509. auto wrappedCallback = [innerCallback = rawToUniquePtr (callbackIn), mapFn] (int buttonIndex)
  510. {
  511. innerCallback->modalStateFinished (mapFn (buttonIndex));
  512. };
  513. return rawToUniquePtr (ModalCallbackFunction::create (std::move (wrappedCallback)));
  514. }
  515. }
  516. #if JUCE_MODAL_LOOPS_PERMITTED
  517. void AlertWindow::showMessageBox (MessageBoxIconType iconType,
  518. const String& title,
  519. const String& message,
  520. const String& buttonText,
  521. Component* associatedComponent)
  522. {
  523. show (MessageBoxOptions()
  524. .withIconType (iconType)
  525. .withTitle (title)
  526. .withMessage (message)
  527. .withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText)
  528. .withAssociatedComponent (associatedComponent));
  529. }
  530. int AlertWindow::show (const MessageBoxOptions& options)
  531. {
  532. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  533. return NativeMessageBox::show (options);
  534. AlertWindowInfo info (options, nullptr, Async::no);
  535. return info.invoke();
  536. }
  537. bool AlertWindow::showNativeDialogBox (const String& title,
  538. const String& bodyText,
  539. bool isOkCancel)
  540. {
  541. if (isOkCancel)
  542. return NativeMessageBox::showOkCancelBox (AlertWindow::NoIcon, title, bodyText);
  543. NativeMessageBox::showMessageBox (AlertWindow::NoIcon, title, bodyText);
  544. return true;
  545. }
  546. #endif
  547. void AlertWindow::showAsync (const MessageBoxOptions& options, ModalComponentManager::Callback* callback)
  548. {
  549. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  550. {
  551. NativeMessageBox::showAsync (options, callback);
  552. }
  553. else
  554. {
  555. AlertWindowInfo info (options, rawToUniquePtr (callback), Async::yes);
  556. info.invoke();
  557. }
  558. }
  559. void AlertWindow::showAsync (const MessageBoxOptions& options, std::function<void (int)> callback)
  560. {
  561. showAsync (options, ModalCallbackFunction::create (callback));
  562. }
  563. void AlertWindow::showMessageBoxAsync (MessageBoxIconType iconType,
  564. const String& title,
  565. const String& message,
  566. const String& buttonText,
  567. Component* associatedComponent,
  568. ModalComponentManager::Callback* callback)
  569. {
  570. showAsync (MessageBoxOptions()
  571. .withIconType (iconType)
  572. .withTitle (title)
  573. .withMessage (message)
  574. .withButton (buttonText.isEmpty() ? TRANS("OK") : buttonText)
  575. .withAssociatedComponent (associatedComponent),
  576. callback);
  577. }
  578. static int showMaybeAsync (const MessageBoxOptions& options,
  579. ModalComponentManager::Callback* callbackIn,
  580. AlertWindowMappings::MapFn mapFn)
  581. {
  582. const auto showAsync = (callbackIn != nullptr ? Async::yes
  583. : Async::no);
  584. auto callback = AlertWindowMappings::getWrappedCallback (callbackIn, mapFn);
  585. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  586. {
  587. #if JUCE_MODAL_LOOPS_PERMITTED
  588. if (showAsync == Async::no)
  589. return mapFn (NativeMessageBox::show (options));
  590. #endif
  591. NativeMessageBox::showAsync (options, callback.release());
  592. return false;
  593. }
  594. AlertWindowInfo info (options, std::move (callback), showAsync);
  595. return info.invoke();
  596. }
  597. bool AlertWindow::showOkCancelBox (MessageBoxIconType iconType,
  598. const String& title,
  599. const String& message,
  600. const String& button1Text,
  601. const String& button2Text,
  602. Component* associatedComponent,
  603. ModalComponentManager::Callback* callback)
  604. {
  605. return showMaybeAsync (MessageBoxOptions()
  606. .withIconType (iconType)
  607. .withTitle (title)
  608. .withMessage (message)
  609. .withButton (button1Text.isEmpty() ? TRANS("OK") : button1Text)
  610. .withButton (button2Text.isEmpty() ? TRANS("Cancel") : button2Text)
  611. .withAssociatedComponent (associatedComponent),
  612. callback,
  613. LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()
  614. ? AlertWindowMappings::okCancel
  615. : AlertWindowMappings::noMapping) == 1;
  616. }
  617. int AlertWindow::showYesNoCancelBox (MessageBoxIconType iconType,
  618. const String& title,
  619. const String& message,
  620. const String& button1Text,
  621. const String& button2Text,
  622. const String& button3Text,
  623. Component* associatedComponent,
  624. ModalComponentManager::Callback* callback)
  625. {
  626. return showMaybeAsync (MessageBoxOptions()
  627. .withIconType (iconType)
  628. .withTitle (title)
  629. .withMessage (message)
  630. .withButton (button1Text.isEmpty() ? TRANS("Yes") : button1Text)
  631. .withButton (button2Text.isEmpty() ? TRANS("No") : button2Text)
  632. .withButton (button3Text.isEmpty() ? TRANS("Cancel") : button3Text)
  633. .withAssociatedComponent (associatedComponent),
  634. callback,
  635. LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows()
  636. ? AlertWindowMappings::yesNoCancel
  637. : AlertWindowMappings::noMapping);
  638. }
  639. //==============================================================================
  640. std::unique_ptr<AccessibilityHandler> AlertWindow::createAccessibilityHandler()
  641. {
  642. return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::dialogWindow);
  643. }
  644. } // namespace juce