Audio plugin host https://kx.studio/carla
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.

juce_ApplicationCommandManager.h 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. //==============================================================================
  21. /**
  22. One of these objects holds a list of all the commands your app can perform,
  23. and despatches these commands when needed.
  24. Application commands are a good way to trigger actions in your app, e.g. "Quit",
  25. "Copy", "Paste", etc. Menus, buttons and keypresses can all be given commands
  26. to invoke automatically, which means you don't have to handle the result of a menu
  27. or button click manually. Commands are despatched to ApplicationCommandTarget objects
  28. which can choose which events they want to handle.
  29. This architecture also allows for nested ApplicationCommandTargets, so that for example
  30. you could have two different objects, one inside the other, both of which can respond to
  31. a "delete" command. Depending on which one has focus, the command will be sent to the
  32. appropriate place, regardless of whether it was triggered by a menu, keypress or some other
  33. method.
  34. To set up your app to use commands, you'll need to do the following:
  35. - Create a global ApplicationCommandManager to hold the list of all possible
  36. commands. (This will also manage a set of key-mappings for them).
  37. - Make some of your UI components (or other objects) inherit from ApplicationCommandTarget.
  38. This allows the object to provide a list of commands that it can perform, and
  39. to handle them.
  40. - Register each type of command using ApplicationCommandManager::registerAllCommandsForTarget(),
  41. or ApplicationCommandManager::registerCommand().
  42. - If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings()
  43. method to access the key-mapper object, which you will need to register as a key-listener
  44. in whatever top-level component you're using. See the KeyPressMappingSet class for more help
  45. about setting this up.
  46. - Use methods such as PopupMenu::addCommandItem() or Button::setCommandToTrigger() to
  47. cause these commands to be invoked automatically.
  48. - Commands can be invoked directly by your code using ApplicationCommandManager::invokeDirectly().
  49. When a command is invoked, the ApplicationCommandManager will try to choose the best
  50. ApplicationCommandTarget to receive the specified command. To do this it will use the
  51. current keyboard focus to see which component might be interested, and will search the
  52. component hierarchy for those that also implement the ApplicationCommandTarget interface.
  53. If an ApplicationCommandTarget isn't interested in the command that is being invoked, then
  54. the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget()
  55. method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns nullptr.
  56. At this point if the command still hasn't been performed, it will be passed to the current
  57. JUCEApplication object (which is itself an ApplicationCommandTarget).
  58. To exert some custom control over which ApplicationCommandTarget is chosen to invoke a command,
  59. you can override the ApplicationCommandManager::getFirstCommandTarget() method and choose
  60. the object yourself.
  61. @see ApplicationCommandTarget, ApplicationCommandInfo
  62. @tags{GUI}
  63. */
  64. class JUCE_API ApplicationCommandManager : private AsyncUpdater,
  65. private FocusChangeListener
  66. {
  67. public:
  68. //==============================================================================
  69. /** Creates an ApplicationCommandManager.
  70. Once created, you'll need to register all your app's commands with it, using
  71. ApplicationCommandManager::registerAllCommandsForTarget() or
  72. ApplicationCommandManager::registerCommand().
  73. */
  74. ApplicationCommandManager();
  75. /** Destructor.
  76. Make sure that you don't delete this if pointers to it are still being used by
  77. objects such as PopupMenus or Buttons.
  78. */
  79. ~ApplicationCommandManager() override;
  80. //==============================================================================
  81. /** Clears the current list of all commands.
  82. Note that this will also clear the contents of the KeyPressMappingSet.
  83. */
  84. void clearCommands();
  85. /** Adds a command to the list of registered commands.
  86. @see registerAllCommandsForTarget
  87. */
  88. void registerCommand (const ApplicationCommandInfo& newCommand);
  89. /** Adds all the commands that this target publishes to the manager's list.
  90. This will use ApplicationCommandTarget::getAllCommands() and ApplicationCommandTarget::getCommandInfo()
  91. to get details about all the commands that this target can do, and will call
  92. registerCommand() to add each one to the manger's list.
  93. @see registerCommand
  94. */
  95. void registerAllCommandsForTarget (ApplicationCommandTarget* target);
  96. /** Removes the command with a specified ID.
  97. Note that this will also remove any key mappings that are mapped to the command.
  98. */
  99. void removeCommand (CommandID commandID);
  100. /** This should be called to tell the manager that one of its registered commands may have changed
  101. its active status.
  102. Because the command manager only finds out whether a command is active or inactive by querying
  103. the current ApplicationCommandTarget, this is used to tell it that things may have changed. It
  104. allows things like buttons to update their enablement, etc.
  105. This method will cause an asynchronous call to ApplicationCommandManagerListener::applicationCommandListChanged()
  106. for any registered listeners.
  107. */
  108. void commandStatusChanged();
  109. //==============================================================================
  110. /** Returns the number of commands that have been registered.
  111. @see registerCommand
  112. */
  113. int getNumCommands() const noexcept { return commands.size(); }
  114. /** Returns the details about one of the registered commands.
  115. The index is between 0 and (getNumCommands() - 1).
  116. */
  117. const ApplicationCommandInfo* getCommandForIndex (int index) const noexcept { return commands [index]; }
  118. /** Returns the details about a given command ID.
  119. This will search the list of registered commands for one with the given command
  120. ID number, and return its associated info. If no matching command is found, this
  121. will return nullptr.
  122. */
  123. const ApplicationCommandInfo* getCommandForID (CommandID commandID) const noexcept;
  124. /** Returns the name field for a command.
  125. An empty string is returned if no command with this ID has been registered.
  126. @see getDescriptionOfCommand
  127. */
  128. String getNameOfCommand (CommandID commandID) const noexcept;
  129. /** Returns the description field for a command.
  130. An empty string is returned if no command with this ID has been registered. If the
  131. command has no description, this will return its short name field instead.
  132. @see getNameOfCommand
  133. */
  134. String getDescriptionOfCommand (CommandID commandID) const noexcept;
  135. /** Returns the list of categories.
  136. This will go through all registered commands, and return a list of all the distinct
  137. categoryName values from their ApplicationCommandInfo structure.
  138. @see getCommandsInCategory()
  139. */
  140. StringArray getCommandCategories() const;
  141. /** Returns a list of all the command UIDs in a particular category.
  142. @see getCommandCategories()
  143. */
  144. Array<CommandID> getCommandsInCategory (const String& categoryName) const;
  145. //==============================================================================
  146. /** Returns the manager's internal set of key mappings.
  147. This object can be used to edit the keypresses. To actually link this object up
  148. to invoke commands when a key is pressed, see the comments for the KeyPressMappingSet
  149. class.
  150. @see KeyPressMappingSet
  151. */
  152. KeyPressMappingSet* getKeyMappings() const noexcept { return keyMappings.get(); }
  153. //==============================================================================
  154. /** Invokes the given command directly, sending it to the default target.
  155. This is just an easy way to call invoke() without having to fill out the InvocationInfo
  156. structure.
  157. */
  158. bool invokeDirectly (CommandID commandID, bool asynchronously);
  159. /** Sends a command to the default target.
  160. This will choose a target using getFirstCommandTarget(), and send the specified command
  161. to it using the ApplicationCommandTarget::invoke() method. This means that if the
  162. first target can't handle the command, it will be passed on to targets further down the
  163. chain (see ApplicationCommandTarget::invoke() for more info).
  164. @param invocationInfo this must be correctly filled-in, describing the context for
  165. the invocation.
  166. @param asynchronously if false, the command will be performed before this method returns.
  167. If true, a message will be posted so that the command will be performed
  168. later on the message thread, and this method will return immediately.
  169. @see ApplicationCommandTarget::invoke
  170. */
  171. bool invoke (const ApplicationCommandTarget::InvocationInfo& invocationInfo,
  172. bool asynchronously);
  173. //==============================================================================
  174. /** Chooses the ApplicationCommandTarget to which a command should be sent.
  175. Whenever the manager needs to know which target a command should be sent to, it calls
  176. this method to determine the first one to try.
  177. By default, this method will return the target that was set by calling setFirstCommandTarget().
  178. If no target is set, it will return the result of findDefaultComponentTarget().
  179. If you need to make sure all commands go via your own custom target, then you can
  180. either use setFirstCommandTarget() to specify a single target, or override this method
  181. if you need more complex logic to choose one.
  182. It may return nullptr if no targets are available.
  183. @see getTargetForCommand, invoke, invokeDirectly
  184. */
  185. virtual ApplicationCommandTarget* getFirstCommandTarget (CommandID commandID);
  186. /** Sets a target to be returned by getFirstCommandTarget().
  187. If this is set to nullptr, then getFirstCommandTarget() will by default return the
  188. result of findDefaultComponentTarget().
  189. If you use this to set a target, make sure you call setFirstCommandTarget(nullptr)
  190. before deleting the target object.
  191. */
  192. void setFirstCommandTarget (ApplicationCommandTarget* newTarget) noexcept;
  193. /** Tries to find the best target to use to perform a given command.
  194. This will call getFirstCommandTarget() to find the preferred target, and will
  195. check whether that target can handle the given command. If it can't, then it'll use
  196. ApplicationCommandTarget::getNextCommandTarget() to find the next one to try, and
  197. so on until no more are available.
  198. If no targets are found that can perform the command, this method will return nullptr.
  199. If a target is found, then it will get the target to fill-in the upToDateInfo
  200. structure with the latest info about that command, so that the caller can see
  201. whether the command is disabled, ticked, etc.
  202. */
  203. ApplicationCommandTarget* getTargetForCommand (CommandID commandID,
  204. ApplicationCommandInfo& upToDateInfo);
  205. //==============================================================================
  206. /** Registers a listener that will be called when various events occur. */
  207. void addListener (ApplicationCommandManagerListener* listener);
  208. /** Deregisters a previously-added listener. */
  209. void removeListener (ApplicationCommandManagerListener* listener);
  210. //==============================================================================
  211. /** Looks for a suitable command target based on which Components have the keyboard focus.
  212. This is used by the default implementation of ApplicationCommandTarget::getFirstCommandTarget(),
  213. but is exposed here in case it's useful.
  214. It tries to pick the best ApplicationCommandTarget by looking at focused components, top level
  215. windows, etc., and using the findTargetForComponent() method.
  216. */
  217. static ApplicationCommandTarget* findDefaultComponentTarget();
  218. /** Examines this component and all its parents in turn, looking for the first one
  219. which is an ApplicationCommandTarget.
  220. Returns the first ApplicationCommandTarget that it finds, or nullptr if none of them
  221. implement that class.
  222. */
  223. static ApplicationCommandTarget* findTargetForComponent (Component*);
  224. private:
  225. //==============================================================================
  226. OwnedArray<ApplicationCommandInfo> commands;
  227. ListenerList<ApplicationCommandManagerListener> listeners;
  228. std::unique_ptr<KeyPressMappingSet> keyMappings;
  229. ApplicationCommandTarget* firstTarget = nullptr;
  230. void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo&);
  231. void handleAsyncUpdate() override;
  232. void globalFocusChanged (Component*) override;
  233. ApplicationCommandInfo* getMutableCommandForID (CommandID) const noexcept;
  234. #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
  235. // This is just here to cause a compile error in old code that hasn't been changed to use the new
  236. // version of this method.
  237. virtual short getFirstCommandTarget() { return 0; }
  238. #endif
  239. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationCommandManager)
  240. };
  241. //==============================================================================
  242. /**
  243. A listener that receives callbacks from an ApplicationCommandManager when
  244. commands are invoked or the command list is changed.
  245. @see ApplicationCommandManager::addListener, ApplicationCommandManager::removeListener
  246. @tags{GUI}
  247. */
  248. class JUCE_API ApplicationCommandManagerListener
  249. {
  250. public:
  251. //==============================================================================
  252. /** Destructor. */
  253. virtual ~ApplicationCommandManagerListener() = default;
  254. /** Called when an app command is about to be invoked. */
  255. virtual void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&) = 0;
  256. /** Called when commands are registered or deregistered from the
  257. command manager, or when commands are made active or inactive.
  258. Note that if you're using this to watch for changes to whether a command is disabled,
  259. you'll need to make sure that ApplicationCommandManager::commandStatusChanged() is called
  260. whenever the status of your command might have changed.
  261. */
  262. virtual void applicationCommandListChanged() = 0;
  263. };
  264. } // namespace juce