The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

787 lines
25KB

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