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.

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