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.

800 lines
26KB

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