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.

413 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #ifndef __JUCE_POPUPMENU_JUCEHEADER__
  24. #define __JUCE_POPUPMENU_JUCEHEADER__
  25. #include "juce_PopupMenuCustomComponent.h"
  26. #include "../../../application/juce_ApplicationCommandManager.h"
  27. //==============================================================================
  28. /** Creates and displays a popup-menu.
  29. To show a popup-menu, you create one of these, add some items to it, then
  30. call its show() method, which returns the id of the item the user selects.
  31. E.g. @code
  32. void MyWidget::mouseDown (const MouseEvent& e)
  33. {
  34. PopupMenu m;
  35. m.addItem (1, "item 1");
  36. m.addItem (2, "item 2");
  37. const int result = m.show();
  38. if (result == 0)
  39. {
  40. // user dismissed the menu without picking anything
  41. }
  42. else if (result == 1)
  43. {
  44. // user picked item 1
  45. }
  46. else if (result == 2)
  47. {
  48. // user picked item 2
  49. }
  50. }
  51. @endcode
  52. Submenus are easy too: @code
  53. void MyWidget::mouseDown (const MouseEvent& e)
  54. {
  55. PopupMenu subMenu;
  56. subMenu.addItem (1, "item 1");
  57. subMenu.addItem (2, "item 2");
  58. PopupMenu mainMenu;
  59. mainMenu.addItem (3, "item 3");
  60. mainMenu.addSubMenu ("other choices", subMenu);
  61. const int result = m.show();
  62. ...etc
  63. }
  64. @endcode
  65. */
  66. class JUCE_API PopupMenu
  67. {
  68. public:
  69. //==============================================================================
  70. /** Creates an empty popup menu. */
  71. PopupMenu() throw();
  72. /** Creates a copy of another menu. */
  73. PopupMenu (const PopupMenu& other) throw();
  74. /** Destructor. */
  75. ~PopupMenu() throw();
  76. /** Copies this menu from another one. */
  77. const PopupMenu& operator= (const PopupMenu& other) throw();
  78. //==============================================================================
  79. /** Resets the menu, removing all its items. */
  80. void clear() throw();
  81. /** Appends a new text item for this menu to show.
  82. @param itemResultId the number that will be returned from the show() method
  83. if the user picks this item. The value should never be
  84. zero, because that's used to indicate that the user didn't
  85. select anything.
  86. @param itemText the text to show.
  87. @param isActive if false, the item will be shown 'greyed-out' and can't be
  88. picked
  89. @param isTicked if true, the item will be shown with a tick next to it
  90. @param iconToUse if this is non-zero, it should be an image that will be
  91. displayed to the left of the item. This method will take its
  92. own copy of the image passed-in, so there's no need to keep
  93. it hanging around.
  94. @see addSeparator, addColouredItem, addCustomItem, addSubMenu
  95. */
  96. void addItem (const int itemResultId,
  97. const String& itemText,
  98. const bool isActive = true,
  99. const bool isTicked = false,
  100. const Image* const iconToUse = 0) throw();
  101. /** Adds an item that represents one of the commands in a command manager object.
  102. @param commandManager the manager to use to trigger the command and get information
  103. about it
  104. @param commandID the ID of the command
  105. @param displayName if this is non-empty, then this string will be used instead of
  106. the command's registered name
  107. */
  108. void addCommandItem (ApplicationCommandManager* commandManager,
  109. const int commandID,
  110. const String& displayName = String::empty) throw();
  111. /** Appends a text item with a special colour.
  112. This is the same as addItem(), but specifies a colour to use for the
  113. text, which will override the default colours that are used by the
  114. current look-and-feel. See addItem() for a description of the parameters.
  115. */
  116. void addColouredItem (const int itemResultId,
  117. const String& itemText,
  118. const Colour& itemTextColour,
  119. const bool isActive = true,
  120. const bool isTicked = false,
  121. const Image* const iconToUse = 0) throw();
  122. /** Appends a custom menu item.
  123. This will add a user-defined component to use as a menu item. The component
  124. passed in will be deleted by this menu when it's no longer needed.
  125. @see PopupMenuCustomComponent
  126. */
  127. void addCustomItem (const int itemResultId,
  128. PopupMenuCustomComponent* const customComponent) throw();
  129. /** Appends a custom menu item that can't be used to trigger a result.
  130. This will add a user-defined component to use as a menu item. Unlike the
  131. addCustomItem() method that takes a PopupMenuCustomComponent, this version
  132. can't trigger a result from it, so doesn't take a menu ID. It also doesn't
  133. delete the component when it's finished, so it's the caller's responsibility
  134. to manage the component that is passed-in.
  135. if triggerMenuItemAutomaticallyWhenClicked is true, the menu itself will handle
  136. detection of a mouse-click on your component, and use that to trigger the
  137. menu ID specified in itemResultId. If this is false, the menu item can't
  138. be triggered, so itemResultId is not used.
  139. @see PopupMenuCustomComponent
  140. */
  141. void addCustomItem (const int itemResultId,
  142. Component* customComponent,
  143. int idealWidth, int idealHeight,
  144. const bool triggerMenuItemAutomaticallyWhenClicked) throw();
  145. /** Appends a sub-menu.
  146. If the menu that's passed in is empty, it will appear as an inactive item.
  147. */
  148. void addSubMenu (const String& subMenuName,
  149. const PopupMenu& subMenu,
  150. const bool isActive = true,
  151. Image* const iconToUse = 0) throw();
  152. /** Appends a separator to the menu, to help break it up into sections.
  153. The menu class is smart enough not to display separators at the top or bottom
  154. of the menu, and it will replace mutliple adjacent separators with a single
  155. one, so your code can be quite free and easy about adding these, and it'll
  156. always look ok.
  157. */
  158. void addSeparator() throw();
  159. /** Adds a non-clickable text item to the menu.
  160. This is a bold-font items which can be used as a header to separate the items
  161. into named groups.
  162. */
  163. void addSectionHeader (const String& title) throw();
  164. /** Returns the number of items that the menu currently contains.
  165. (This doesn't count separators).
  166. */
  167. int getNumItems() const throw();
  168. /** Returns true if the menu contains a command item that triggers the given command. */
  169. bool containsCommandItem (const int commandID) const throw();
  170. /** Returns true if the menu contains any items that can be used. */
  171. bool containsAnyActiveItems() const throw();
  172. //==============================================================================
  173. /** Displays the menu and waits for the user to pick something.
  174. This will display the menu modally, and return the ID of the item that the
  175. user picks. If they click somewhere off the menu to get rid of it without
  176. choosing anything, this will return 0.
  177. The current location of the mouse will be used as the position to show the
  178. menu - to explicitly set the menu's position, use showAt() instead. Depending
  179. on where this point is on the screen, the menu will appear above, below or
  180. to the side of the point.
  181. @param itemIdThatMustBeVisible if you set this to the ID of one of the menu items,
  182. then when the menu first appears, it will make sure
  183. that this item is visible. So if the menu has too many
  184. items to fit on the screen, it will be scrolled to a
  185. position where this item is visible.
  186. @param minimumWidth a minimum width for the menu, in pixels. It may be wider
  187. than this if some items are too long to fit.
  188. @param maximumNumColumns if there are too many items to fit on-screen in a single
  189. vertical column, the menu may be laid out as a series of
  190. columns - this is the maximum number allowed. To use the
  191. default value for this (probably about 7), you can pass
  192. in zero.
  193. @param standardItemHeight if this is non-zero, it will be used as the standard
  194. height for menu items (apart from custom items)
  195. @see showAt
  196. */
  197. int show (const int itemIdThatMustBeVisible = 0,
  198. const int minimumWidth = 0,
  199. const int maximumNumColumns = 0,
  200. const int standardItemHeight = 0);
  201. /** Displays the menu at a specific location.
  202. This is the same as show(), but uses a specific location (in global screen
  203. co-ordinates) rather than the current mouse position.
  204. Note that the co-ordinates don't specify the top-left of the menu - they
  205. indicate a point of interest, and the menu will position itself nearby to
  206. this point, trying to keep it fully on-screen.
  207. @see show()
  208. */
  209. int showAt (const int screenX,
  210. const int screenY,
  211. const int itemIdThatMustBeVisible = 0,
  212. const int minimumWidth = 0,
  213. const int maximumNumColumns = 0,
  214. const int standardItemHeight = 0);
  215. /** Displays the menu as if it's attached to a component such as a button.
  216. This is similar to showAt(), but will position it next to the given component, e.g.
  217. so that the menu's edge is aligned with that of the component. This is intended for
  218. things like buttons that trigger a pop-up menu.
  219. */
  220. int showAt (Component* componentToAttachTo,
  221. const int itemIdThatMustBeVisible = 0,
  222. const int minimumWidth = 0,
  223. const int maximumNumColumns = 0,
  224. const int standardItemHeight = 0);
  225. //==============================================================================
  226. /** Closes any menus that are currently open.
  227. This might be useful if you have a situation where your window is being closed
  228. by some means other than a user action, and you'd like to make sure that menus
  229. aren't left hanging around.
  230. */
  231. static void JUCE_CALLTYPE dismissAllActiveMenus() throw();
  232. //==============================================================================
  233. /** Specifies a look-and-feel for the menu and any sub-menus that it has.
  234. This can be called before show() if you need a customised menu. Be careful
  235. not to delete the LookAndFeel object before the menu has been deleted.
  236. */
  237. void setLookAndFeel (LookAndFeel* const newLookAndFeel) throw();
  238. //==============================================================================
  239. /** A set of colour IDs to use to change the colour of various aspects of the menu.
  240. These constants can be used either via the LookAndFeel::setColour()
  241. method for the look and feel that is set for this menu with setLookAndFeel()
  242. @see setLookAndFeel, LookAndFeel::setColour, LookAndFeel::findColour
  243. */
  244. enum ColourIds
  245. {
  246. backgroundColourId = 0x1000700, /**< The colour to fill the menu's background with. */
  247. textColourId = 0x1000600, /**< The colour for normal menu item text, (unless the
  248. colour is specified when the item is added). */
  249. headerTextColourId = 0x1000601, /**< The colour for section header item text (see the
  250. addSectionHeader() method). */
  251. highlightedBackgroundColourId = 0x1000900, /**< The colour to fill the background of the currently
  252. highlighted menu item. */
  253. highlightedTextColourId = 0x1000800, /**< The colour to use for the text of the currently
  254. highlighted item. */
  255. };
  256. //==============================================================================
  257. /**
  258. Allows you to iterate through the items in a pop-up menu, and examine
  259. their properties.
  260. To use this, just create one and repeatedly call its next() method. When this
  261. returns true, all the member variables of the iterator are filled-out with
  262. information describing the menu item. When it returns false, the end of the
  263. list has been reached.
  264. */
  265. class JUCE_API MenuItemIterator
  266. {
  267. public:
  268. //==============================================================================
  269. /** Creates an iterator that will scan through the items in the specified
  270. menu.
  271. Be careful not to add any items to a menu while it is being iterated,
  272. or things could get out of step.
  273. */
  274. MenuItemIterator (const PopupMenu& menu) throw();
  275. /** Destructor. */
  276. ~MenuItemIterator() throw();
  277. /** Returns true if there is another item, and sets up all this object's
  278. member variables to reflect that item's properties.
  279. */
  280. bool next() throw();
  281. //==============================================================================
  282. String itemName;
  283. const PopupMenu* subMenu;
  284. int itemId;
  285. bool isSeparator;
  286. bool isTicked;
  287. bool isEnabled;
  288. bool isCustomComponent;
  289. bool isSectionHeader;
  290. const Colour* customColour;
  291. const Image* customImage;
  292. ApplicationCommandManager* commandManager;
  293. //==============================================================================
  294. juce_UseDebuggingNewOperator
  295. private:
  296. const PopupMenu& menu;
  297. int index;
  298. MenuItemIterator (const MenuItemIterator&);
  299. const MenuItemIterator& operator= (const MenuItemIterator&);
  300. };
  301. //==============================================================================
  302. juce_UseDebuggingNewOperator
  303. private:
  304. friend class PopupMenuWindow;
  305. friend class MenuItemIterator;
  306. VoidArray items;
  307. LookAndFeel* lookAndFeel;
  308. bool separatorPending;
  309. void addSeparatorIfPending();
  310. int showMenu (const int x, const int y, const int w, const int h,
  311. const int itemIdThatMustBeVisible,
  312. const int minimumWidth,
  313. const int maximumNumColumns,
  314. const int standardItemHeight,
  315. const bool alignToRectangle,
  316. Component* const componentAttachedTo) throw();
  317. friend class MenuBarComponent;
  318. Component* createMenuComponent (const int x, const int y, const int w, const int h,
  319. const int itemIdThatMustBeVisible,
  320. const int minimumWidth,
  321. const int maximumNumColumns,
  322. const int standardItemHeight,
  323. const bool alignToRectangle,
  324. Component* menuBarComponent,
  325. ApplicationCommandManager** managerOfChosenCommand,
  326. Component* const componentAttachedTo) throw();
  327. };
  328. #endif // __JUCE_POPUPMENU_JUCEHEADER__