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.

189 lines
5.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase
  20. {
  21. public:
  22. CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf)
  23. : owner (target), info (inf)
  24. {
  25. }
  26. void messageCallback() override
  27. {
  28. if (ApplicationCommandTarget* const target = owner)
  29. target->tryToInvoke (info, false);
  30. }
  31. private:
  32. WeakReference<ApplicationCommandTarget> owner;
  33. const InvocationInfo info;
  34. JUCE_DECLARE_NON_COPYABLE (CommandMessage)
  35. };
  36. //==============================================================================
  37. ApplicationCommandTarget::ApplicationCommandTarget()
  38. {
  39. }
  40. ApplicationCommandTarget::~ApplicationCommandTarget()
  41. {
  42. masterReference.clear();
  43. }
  44. //==============================================================================
  45. bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bool async)
  46. {
  47. if (isCommandActive (info.commandID))
  48. {
  49. if (async)
  50. {
  51. (new CommandMessage (this, info))->post();
  52. return true;
  53. }
  54. if (perform (info))
  55. return true;
  56. // Hmm.. your target claimed that it could perform this command, but failed to do so.
  57. // If it can't do it at the moment for some reason, it should clear the 'isActive' flag
  58. // when it returns the command's info.
  59. jassertfalse;
  60. }
  61. return false;
  62. }
  63. ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent()
  64. {
  65. if (Component* const c = dynamic_cast<Component*> (this))
  66. return c->findParentComponentOfClass<ApplicationCommandTarget>();
  67. return nullptr;
  68. }
  69. ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const CommandID commandID)
  70. {
  71. ApplicationCommandTarget* target = this;
  72. int depth = 0;
  73. while (target != nullptr)
  74. {
  75. Array<CommandID> commandIDs;
  76. target->getAllCommands (commandIDs);
  77. if (commandIDs.contains (commandID))
  78. return target;
  79. target = target->getNextCommandTarget();
  80. ++depth;
  81. jassert (depth < 100); // could be a recursive command chain??
  82. jassert (target != this); // definitely a recursive command chain!
  83. if (depth > 100 || target == this)
  84. break;
  85. }
  86. if (target == nullptr)
  87. {
  88. target = JUCEApplication::getInstance();
  89. if (target != nullptr)
  90. {
  91. Array<CommandID> commandIDs;
  92. target->getAllCommands (commandIDs);
  93. if (commandIDs.contains (commandID))
  94. return target;
  95. }
  96. }
  97. return nullptr;
  98. }
  99. bool ApplicationCommandTarget::isCommandActive (const CommandID commandID)
  100. {
  101. ApplicationCommandInfo info (commandID);
  102. info.flags = ApplicationCommandInfo::isDisabled;
  103. getCommandInfo (commandID, info);
  104. return (info.flags & ApplicationCommandInfo::isDisabled) == 0;
  105. }
  106. //==============================================================================
  107. bool ApplicationCommandTarget::invoke (const InvocationInfo& info, const bool async)
  108. {
  109. ApplicationCommandTarget* target = this;
  110. int depth = 0;
  111. while (target != nullptr)
  112. {
  113. if (target->tryToInvoke (info, async))
  114. return true;
  115. target = target->getNextCommandTarget();
  116. ++depth;
  117. jassert (depth < 100); // could be a recursive command chain??
  118. jassert (target != this); // definitely a recursive command chain!
  119. if (depth > 100 || target == this)
  120. break;
  121. }
  122. if (target == nullptr)
  123. {
  124. target = JUCEApplication::getInstance();
  125. if (target != nullptr)
  126. return target->tryToInvoke (info, async);
  127. }
  128. return false;
  129. }
  130. bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const bool asynchronously)
  131. {
  132. ApplicationCommandTarget::InvocationInfo info (commandID);
  133. info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct;
  134. return invoke (info, asynchronously);
  135. }
  136. //==============================================================================
  137. ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command)
  138. : commandID (command),
  139. commandFlags (0),
  140. invocationMethod (direct),
  141. originatingComponent (nullptr),
  142. isKeyDown (false),
  143. millisecsSinceKeyPressed (0)
  144. {
  145. }