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.

592 lines
30KB

  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. //==============================================================================
  21. /** A window that displays a message and has buttons for the user to react to it.
  22. For simple dialog boxes with just a couple of buttons on them, there are
  23. some static methods for running these.
  24. For more complex dialogs, an AlertWindow can be created, then it can have some
  25. buttons and components added to it, and its enterModalState() method is used to
  26. show it. The value returned to the ModalComponentManager::Callback shows
  27. which button the user pressed to dismiss the box.
  28. @see ThreadWithProgressWindow, Component::enterModalState
  29. @tags{GUI}
  30. */
  31. class JUCE_API AlertWindow : public TopLevelWindow
  32. {
  33. public:
  34. //==============================================================================
  35. /** Creates an AlertWindow.
  36. @param title the headline to show at the top of the dialog box
  37. @param message a longer, more descriptive message to show underneath the
  38. headline
  39. @param iconType the type of icon to display
  40. @param associatedComponent if this is non-null, it specifies the component that the
  41. alert window should be associated with. Depending on the look
  42. and feel, this might be used for positioning of the alert window.
  43. */
  44. AlertWindow (const String& title,
  45. const String& message,
  46. MessageBoxIconType iconType,
  47. Component* associatedComponent = nullptr);
  48. /** Destroys the AlertWindow */
  49. ~AlertWindow() override;
  50. //==============================================================================
  51. /** Returns the type of alert icon that was specified when the window
  52. was created. */
  53. MessageBoxIconType getAlertType() const noexcept { return alertIconType; }
  54. //==============================================================================
  55. /** Changes the dialog box's message.
  56. This will also resize the window to fit the new message if required.
  57. */
  58. void setMessage (const String& message);
  59. //==============================================================================
  60. /** Adds a button to the window.
  61. @param name the text to show on the button
  62. @param returnValue the value that should be returned from runModalLoop()
  63. if this is the button that the user presses.
  64. @param shortcutKey1 an optional key that can be pressed to trigger this button
  65. @param shortcutKey2 a second optional key that can be pressed to trigger this button
  66. */
  67. void addButton (const String& name,
  68. int returnValue,
  69. const KeyPress& shortcutKey1 = KeyPress(),
  70. const KeyPress& shortcutKey2 = KeyPress());
  71. /** Returns the number of buttons that the window currently has. */
  72. int getNumButtons() const;
  73. /** Returns a Button that was added to the AlertWindow.
  74. @param index the index of the button in order that it was added with the addButton() method.
  75. @returns the Button component, or nullptr if the index is out of bounds.
  76. @see getNumButtons
  77. */
  78. Button* getButton (int index) const;
  79. /** Returns a Button that was added to the AlertWindow.
  80. @param buttonName the name that was passed into the addButton() method
  81. @returns the Button component, or nullptr if none was found for the given name.
  82. */
  83. Button* getButton (const String& buttonName) const;
  84. /** Invokes a click of one of the buttons. */
  85. void triggerButtonClick (const String& buttonName);
  86. /** If set to true and the window contains no buttons, then pressing the escape key will make
  87. the alert cancel its modal state.
  88. By default this setting is true - turn it off if you don't want the box to respond to
  89. the escape key. Note that it is ignored if you have any buttons, and in that case you
  90. should give the buttons appropriate keypresses to trigger cancelling if you want to.
  91. */
  92. void setEscapeKeyCancels (bool shouldEscapeKeyCancel);
  93. //==============================================================================
  94. /** Adds a textbox to the window for entering strings.
  95. @param name an internal name for the text-box. This is the name to pass to
  96. the getTextEditorContents() method to find out what the
  97. user typed-in.
  98. @param initialContents a string to show in the text box when it's first shown
  99. @param onScreenLabel if this is non-empty, it will be displayed next to the
  100. text-box to label it.
  101. @param isPasswordBox if true, the text editor will display asterisks instead of
  102. the actual text
  103. @see getTextEditorContents
  104. */
  105. void addTextEditor (const String& name,
  106. const String& initialContents,
  107. const String& onScreenLabel = String(),
  108. bool isPasswordBox = false);
  109. /** Returns the contents of a named textbox.
  110. After showing an AlertWindow that contains a text editor, this can be
  111. used to find out what the user has typed into it.
  112. @param nameOfTextEditor the name of the text box that you're interested in
  113. @see addTextEditor
  114. */
  115. String getTextEditorContents (const String& nameOfTextEditor) const;
  116. /** Returns a pointer to a textbox that was added with addTextEditor(). */
  117. TextEditor* getTextEditor (const String& nameOfTextEditor) const;
  118. //==============================================================================
  119. /** Adds a drop-down list of choices to the box.
  120. After the box has been shown, the getComboBoxComponent() method can
  121. be used to find out which item the user picked.
  122. @param name the label to use for the drop-down list
  123. @param items the list of items to show in it
  124. @param onScreenLabel if this is non-empty, it will be displayed next to the
  125. combo-box to label it.
  126. @see getComboBoxComponent
  127. */
  128. void addComboBox (const String& name,
  129. const StringArray& items,
  130. const String& onScreenLabel = String());
  131. /** Returns a drop-down list that was added to the AlertWindow.
  132. @param nameOfList the name that was passed into the addComboBox() method
  133. when creating the drop-down
  134. @returns the ComboBox component, or nullptr if none was found for the given name.
  135. */
  136. ComboBox* getComboBoxComponent (const String& nameOfList) const;
  137. //==============================================================================
  138. /** Adds a block of text.
  139. This is handy for adding a multi-line note next to a textbox or combo-box,
  140. to provide more details about what's going on.
  141. */
  142. void addTextBlock (const String& text);
  143. //==============================================================================
  144. /** Adds a progress-bar to the window.
  145. @param progressValue a variable that will be repeatedly checked while the
  146. dialog box is visible, to see how far the process has
  147. got. The value should be in the range 0 to 1.0
  148. @param style determines the style the ProgressBar should adopt.
  149. By default this use a style automatically chosen by
  150. the LookAndFeel, but you can force a particular style
  151. by passing a non-optional value.
  152. @see ProgressBar::setStyle
  153. */
  154. void addProgressBarComponent (double& progressValue, std::optional<ProgressBar::Style> style = std::nullopt);
  155. //==============================================================================
  156. /** Adds a user-defined component to the dialog box.
  157. @param component the component to add - its size should be set up correctly
  158. before it is passed in. The caller is responsible for deleting
  159. the component later on - the AlertWindow won't delete it.
  160. */
  161. void addCustomComponent (Component* component);
  162. /** Returns the number of custom components in the dialog box.
  163. @see getCustomComponent, addCustomComponent
  164. */
  165. int getNumCustomComponents() const;
  166. /** Returns one of the custom components in the dialog box.
  167. @param index a value 0 to (getNumCustomComponents() - 1).
  168. Out-of-range indexes will return nullptr
  169. @see getNumCustomComponents, addCustomComponent
  170. */
  171. Component* getCustomComponent (int index) const;
  172. /** Removes one of the custom components in the dialog box.
  173. Note that this won't delete it, it just removes the component from the window
  174. @param index a value 0 to (getNumCustomComponents() - 1).
  175. Out-of-range indexes will return nullptr
  176. @returns the component that was removed (or null)
  177. @see getNumCustomComponents, addCustomComponent
  178. */
  179. Component* removeCustomComponent (int index);
  180. //==============================================================================
  181. /** Returns true if the window contains any components other than just buttons.*/
  182. bool containsAnyExtraComponents() const;
  183. //==============================================================================
  184. #if JUCE_MODAL_LOOPS_PERMITTED
  185. /** Shows a dialog box that just has a message and a single button to get rid of it.
  186. The box is shown modally, and the method will block until the user has clicked the
  187. button (or pressed the escape or return keys).
  188. @param iconType the type of icon to show
  189. @param title the headline to show at the top of the box
  190. @param message a longer, more descriptive message to show underneath the
  191. headline
  192. @param buttonText the text to show in the button - if this string is empty, the
  193. default string "OK" (or a localised version) will be used.
  194. @param associatedComponent if this is non-null, it specifies the component that the
  195. alert window should be associated with. Depending on the look
  196. and feel, this might be used for positioning of the alert window.
  197. */
  198. static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType,
  199. const String& title,
  200. const String& message,
  201. const String& buttonText = String(),
  202. Component* associatedComponent = nullptr);
  203. /** Shows a dialog box using the specified options.
  204. The box is shown modally, and the method will block until the user dismisses it.
  205. @param options the options to use when creating the dialog.
  206. @returns the index of the button that was clicked.
  207. @see MessageBoxOptions
  208. */
  209. static int JUCE_CALLTYPE show (const MessageBoxOptions& options);
  210. #endif
  211. /** Shows a dialog box using the specified options.
  212. The box will be displayed and placed into a modal state, but this method will return
  213. immediately, and the callback will be invoked later when the user dismisses the box.
  214. @param options the options to use when creating the dialog.
  215. @param callback if this is non-null, the callback will receive a call to its
  216. modalStateFinished() when the box is dismissed with the index of the
  217. button that was clicked as its argument.
  218. The callback object will be owned and deleted by the system, so make sure
  219. that it works safely and doesn't keep any references to objects that might
  220. be deleted before it gets called.
  221. @see MessageBoxOptions
  222. */
  223. static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
  224. ModalComponentManager::Callback* callback);
  225. /** Shows a dialog box using the specified options.
  226. The box will be displayed and placed into a modal state, but this method will return
  227. immediately, and the callback will be invoked later when the user dismisses the box.
  228. @param options the options to use when creating the dialog.
  229. @param callback if this is non-null, the callback will be called when the box is
  230. dismissed with the index of the button that was clicked as its argument.
  231. @see MessageBoxOptions
  232. */
  233. static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
  234. std::function<void (int)> callback);
  235. /** Shows a dialog box that just has a message and a single button to get rid of it.
  236. The box will be displayed and placed into a modal state, but this method will
  237. return immediately, and if a callback was supplied, it will be invoked later
  238. when the user dismisses the box.
  239. @param iconType the type of icon to show
  240. @param title the headline to show at the top of the box
  241. @param message a longer, more descriptive message to show underneath the
  242. headline
  243. @param buttonText the text to show in the button - if this string is empty, the
  244. default string "OK" (or a localised version) will be used.
  245. @param associatedComponent if this is non-null, it specifies the component that the
  246. alert window should be associated with. Depending on the look
  247. and feel, this might be used for positioning of the alert window.
  248. @param callback if this is non-null, the callback will receive a call to its
  249. modalStateFinished() when the box is dismissed. The callback object
  250. will be owned and deleted by the system, so make sure that it works
  251. safely and doesn't keep any references to objects that might be deleted
  252. before it gets called.
  253. */
  254. static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
  255. const String& title,
  256. const String& message,
  257. const String& buttonText = String(),
  258. Component* associatedComponent = nullptr,
  259. ModalComponentManager::Callback* callback = nullptr);
  260. /** Shows a dialog box with two buttons.
  261. Ideal for ok/cancel or yes/no choices. The return key can also be used
  262. to trigger the first button, and the escape key for the second button.
  263. If JUCE_MODAL_LOOPS_PERMITTED is not defined or the callback parameter is non-null,
  264. this function will return immediately. The object passed as the callback argument will
  265. receive the result of the alert window asynchronously.
  266. Otherwise, if JUCE_MODAL_LOOPS_PERMITTED is defined and the callback parameter is null,
  267. the box is shown modally, and the method will block until the user has clicked the button
  268. (or pressed the escape or return keys). This mode of operation can cause problems,
  269. especially in plugins, so it is not recommended.
  270. @param iconType the type of icon to show
  271. @param title the headline to show at the top of the box
  272. @param message a longer, more descriptive message to show underneath the
  273. headline
  274. @param button1Text the text to show in the first button - if this string is
  275. empty, the default string "OK" (or a localised version of it)
  276. will be used.
  277. @param button2Text the text to show in the second button - if this string is
  278. empty, the default string "cancel" (or a localised version of it)
  279. will be used.
  280. @param associatedComponent if this is non-null, it specifies the component that the
  281. alert window should be associated with. Depending on the look
  282. and feel, this might be used for positioning of the alert window.
  283. @param callback if this is non-null, the menu will be launched asynchronously,
  284. returning immediately, and the callback will receive a call to its
  285. modalStateFinished() when the box is dismissed, with its parameter
  286. being 1 if the ok button was pressed, or 0 for cancel. The callback object
  287. will be owned and deleted by the system, so make sure that it works
  288. safely and doesn't keep any references to objects that might be deleted
  289. before it gets called.
  290. @returns true if button 1 was clicked, false if it was button 2. If the callback parameter
  291. is not null, the method always returns false, and the user's choice is delivered
  292. later by the callback.
  293. */
  294. static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
  295. const String& title,
  296. const String& message,
  297. #if JUCE_MODAL_LOOPS_PERMITTED
  298. const String& button1Text = String(),
  299. const String& button2Text = String(),
  300. Component* associatedComponent = nullptr,
  301. ModalComponentManager::Callback* callback = nullptr);
  302. #else
  303. const String& button1Text,
  304. const String& button2Text,
  305. Component* associatedComponent,
  306. ModalComponentManager::Callback* callback);
  307. #endif
  308. /** Shows a dialog box with three buttons.
  309. Ideal for yes/no/cancel boxes.
  310. The escape key can be used to trigger the third button.
  311. If JUCE_MODAL_LOOPS_PERMITTED is not defined or the callback parameter is non-null,
  312. this function will return immediately. The object passed as the callback argument will
  313. receive the result of the alert window asynchronously.
  314. Otherwise, if JUCE_MODAL_LOOPS_PERMITTED is defined and the callback parameter is null,
  315. the box is shown modally, and the method will block until the user has clicked the button
  316. (or pressed the escape or return keys). This mode of operation can cause problems,
  317. especially in plugins, so it is not recommended.
  318. @param iconType the type of icon to show
  319. @param title the headline to show at the top of the box
  320. @param message a longer, more descriptive message to show underneath the
  321. headline
  322. @param button1Text the text to show in the first button - if an empty string, then
  323. "yes" will be used (or a localised version of it)
  324. @param button2Text the text to show in the first button - if an empty string, then
  325. "no" will be used (or a localised version of it)
  326. @param button3Text the text to show in the first button - if an empty string, then
  327. "cancel" will be used (or a localised version of it)
  328. @param associatedComponent if this is non-null, it specifies the component that the
  329. alert window should be associated with. Depending on the look
  330. and feel, this might be used for positioning of the alert window.
  331. @param callback if this is non-null, the menu will be launched asynchronously,
  332. returning immediately, and the callback will receive a call to its
  333. modalStateFinished() when the box is dismissed, with its parameter
  334. being 1 if the "yes" button was pressed, 2 for the "no" button, or 0
  335. if it was cancelled. The callback object will be owned and deleted by the
  336. system, so make sure that it works safely and doesn't keep any references
  337. to objects that might be deleted before it gets called.
  338. @returns If the callback parameter has been set, this returns 0. Otherwise, it
  339. returns one of the following values:
  340. - 0 if the third button was pressed (normally used for 'cancel')
  341. - 1 if the first button was pressed (normally used for 'yes')
  342. - 2 if the middle button was pressed (normally used for 'no')
  343. */
  344. static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
  345. const String& title,
  346. const String& message,
  347. #if JUCE_MODAL_LOOPS_PERMITTED
  348. const String& button1Text = String(),
  349. const String& button2Text = String(),
  350. const String& button3Text = String(),
  351. Component* associatedComponent = nullptr,
  352. ModalComponentManager::Callback* callback = nullptr);
  353. #else
  354. const String& button1Text,
  355. const String& button2Text,
  356. const String& button3Text,
  357. Component* associatedComponent,
  358. ModalComponentManager::Callback* callback);
  359. #endif
  360. /** Shows an alert window using the specified options.
  361. The box will be displayed and placed into a modal state, but this method will return
  362. immediately, and the callback will be invoked later when the user dismisses the box.
  363. This function is always asynchronous, even if the callback is null.
  364. The result codes returned by the alert window are as follows.
  365. - One button:
  366. - button[0] returns 0
  367. - Two buttons:
  368. - button[0] returns 1
  369. - button[1] returns 0
  370. - Three buttons:
  371. - button[0] returns 1
  372. - button[1] returns 2
  373. - button[2] returns 0
  374. @param options the options to use when creating the dialog.
  375. @param callback if this is non-null, the callback will receive a call to its
  376. modalStateFinished() when the box is dismissed with the index of the
  377. button that was clicked as its argument.
  378. The callback object will be owned and deleted by the system, so make sure
  379. that it works safely and doesn't keep any references to objects that might
  380. be deleted before it gets called.
  381. @returns a ScopedMessageBox instance. The message box will remain visible for no
  382. longer than the ScopedMessageBox remains alive.
  383. @see MessageBoxOptions
  384. */
  385. [[nodiscard]] static ScopedMessageBox showScopedAsync (const MessageBoxOptions& options,
  386. std::function<void (int)> callback);
  387. //==============================================================================
  388. #if JUCE_MODAL_LOOPS_PERMITTED && ! defined (DOXYGEN)
  389. /** Shows an operating-system native dialog box.
  390. @param title the title to use at the top
  391. @param bodyText the longer message to show
  392. @param isOkCancel if true, this will show an ok/cancel box, if false,
  393. it'll show a box with just an ok button
  394. @returns true if the ok button was pressed, false if they pressed cancel.
  395. */
  396. [[deprecated ("Use the NativeMessageBox methods instead for more options")]]
  397. static bool JUCE_CALLTYPE showNativeDialogBox (const String& title,
  398. const String& bodyText,
  399. bool isOkCancel);
  400. #endif
  401. //==============================================================================
  402. /** A set of colour IDs to use to change the colour of various aspects of the alert box.
  403. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
  404. methods.
  405. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
  406. */
  407. enum ColourIds
  408. {
  409. backgroundColourId = 0x1001800, /**< The background colour for the window. */
  410. textColourId = 0x1001810, /**< The colour for the text. */
  411. outlineColourId = 0x1001820 /**< An optional colour to use to draw a border around the window. */
  412. };
  413. //==============================================================================
  414. /** This abstract base class is implemented by LookAndFeel classes to provide
  415. alert-window drawing functionality.
  416. */
  417. struct JUCE_API LookAndFeelMethods
  418. {
  419. virtual ~LookAndFeelMethods() = default;
  420. virtual AlertWindow* createAlertWindow (const String& title, const String& message,
  421. const String& button1,
  422. const String& button2,
  423. const String& button3,
  424. MessageBoxIconType iconType,
  425. int numButtons,
  426. Component* associatedComponent) = 0;
  427. virtual void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) = 0;
  428. virtual int getAlertBoxWindowFlags() = 0;
  429. virtual Array<int> getWidthsForTextButtons (AlertWindow&, const Array<TextButton*>&) = 0;
  430. virtual int getAlertWindowButtonHeight() = 0;
  431. virtual Font getAlertWindowTitleFont() = 0;
  432. virtual Font getAlertWindowMessageFont() = 0;
  433. virtual Font getAlertWindowFont() = 0;
  434. };
  435. //==============================================================================
  436. using AlertIconType = MessageBoxIconType;
  437. static constexpr auto NoIcon = MessageBoxIconType::NoIcon;
  438. static constexpr auto QuestionIcon = MessageBoxIconType::QuestionIcon;
  439. static constexpr auto WarningIcon = MessageBoxIconType::WarningIcon;
  440. static constexpr auto InfoIcon = MessageBoxIconType::InfoIcon;
  441. /** @internal */
  442. std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
  443. protected:
  444. //==============================================================================
  445. /** @internal */
  446. void paint (Graphics&) override;
  447. /** @internal */
  448. void mouseDown (const MouseEvent&) override;
  449. /** @internal */
  450. void mouseDrag (const MouseEvent&) override;
  451. /** @internal */
  452. bool keyPressed (const KeyPress&) override;
  453. /** @internal */
  454. void lookAndFeelChanged() override;
  455. /** @internal */
  456. void userTriedToCloseWindow() override;
  457. /** @internal */
  458. int getDesktopWindowStyleFlags() const override;
  459. /** @internal */
  460. float getDesktopScaleFactor() const override { return desktopScale * Desktop::getInstance().getGlobalScaleFactor(); }
  461. private:
  462. //==============================================================================
  463. String text;
  464. TextLayout textLayout;
  465. Label accessibleMessageLabel;
  466. MessageBoxIconType alertIconType;
  467. ComponentBoundsConstrainer constrainer;
  468. ComponentDragger dragger;
  469. Rectangle<int> textArea;
  470. OwnedArray<TextButton> buttons;
  471. OwnedArray<TextEditor> textBoxes;
  472. OwnedArray<ComboBox> comboBoxes;
  473. OwnedArray<ProgressBar> progressBars;
  474. Array<Component*> customComps;
  475. OwnedArray<Component> textBlocks;
  476. Array<Component*> allComps;
  477. StringArray textboxNames, comboBoxNames;
  478. Component* const associatedComponent;
  479. bool escapeKeyCancels = true;
  480. float desktopScale = 1.0f;
  481. void exitAlert (Button* button);
  482. void updateLayout (bool onlyIncreaseSize);
  483. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindow)
  484. };
  485. } // namespace juce