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.

194 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. namespace juce
  20. {
  21. class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase
  22. {
  23. public:
  24. CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf)
  25. : owner (target), info (inf)
  26. {
  27. }
  28. void messageCallback() override
  29. {
  30. if (ApplicationCommandTarget* const target = owner)
  31. target->tryToInvoke (info, false);
  32. }
  33. private:
  34. WeakReference<ApplicationCommandTarget> owner;
  35. const InvocationInfo info;
  36. JUCE_DECLARE_NON_COPYABLE (CommandMessage)
  37. };
  38. //==============================================================================
  39. ApplicationCommandTarget::ApplicationCommandTarget()
  40. {
  41. }
  42. ApplicationCommandTarget::~ApplicationCommandTarget()
  43. {
  44. masterReference.clear();
  45. }
  46. //==============================================================================
  47. bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bool async)
  48. {
  49. if (isCommandActive (info.commandID))
  50. {
  51. if (async)
  52. {
  53. (new CommandMessage (this, info))->post();
  54. return true;
  55. }
  56. if (perform (info))
  57. return true;
  58. // Hmm.. your target claimed that it could perform this command, but failed to do so.
  59. // If it can't do it at the moment for some reason, it should clear the 'isActive' flag
  60. // when it returns the command's info.
  61. jassertfalse;
  62. }
  63. return false;
  64. }
  65. ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent()
  66. {
  67. if (Component* const c = dynamic_cast<Component*> (this))
  68. return c->findParentComponentOfClass<ApplicationCommandTarget>();
  69. return nullptr;
  70. }
  71. ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const CommandID commandID)
  72. {
  73. ApplicationCommandTarget* target = this;
  74. int depth = 0;
  75. while (target != nullptr)
  76. {
  77. Array<CommandID> commandIDs;
  78. target->getAllCommands (commandIDs);
  79. if (commandIDs.contains (commandID))
  80. return target;
  81. target = target->getNextCommandTarget();
  82. ++depth;
  83. jassert (depth < 100); // could be a recursive command chain??
  84. jassert (target != this); // definitely a recursive command chain!
  85. if (depth > 100 || target == this)
  86. break;
  87. }
  88. if (target == nullptr)
  89. {
  90. target = JUCEApplication::getInstance();
  91. if (target != nullptr)
  92. {
  93. Array<CommandID> commandIDs;
  94. target->getAllCommands (commandIDs);
  95. if (commandIDs.contains (commandID))
  96. return target;
  97. }
  98. }
  99. return nullptr;
  100. }
  101. bool ApplicationCommandTarget::isCommandActive (const CommandID commandID)
  102. {
  103. ApplicationCommandInfo info (commandID);
  104. info.flags = ApplicationCommandInfo::isDisabled;
  105. getCommandInfo (commandID, info);
  106. return (info.flags & ApplicationCommandInfo::isDisabled) == 0;
  107. }
  108. //==============================================================================
  109. bool ApplicationCommandTarget::invoke (const InvocationInfo& info, const bool async)
  110. {
  111. ApplicationCommandTarget* target = this;
  112. int depth = 0;
  113. while (target != nullptr)
  114. {
  115. if (target->tryToInvoke (info, async))
  116. return true;
  117. target = target->getNextCommandTarget();
  118. ++depth;
  119. jassert (depth < 100); // could be a recursive command chain??
  120. jassert (target != this); // definitely a recursive command chain!
  121. if (depth > 100 || target == this)
  122. break;
  123. }
  124. if (target == nullptr)
  125. {
  126. target = JUCEApplication::getInstance();
  127. if (target != nullptr)
  128. return target->tryToInvoke (info, async);
  129. }
  130. return false;
  131. }
  132. bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const bool asynchronously)
  133. {
  134. ApplicationCommandTarget::InvocationInfo info (commandID);
  135. info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct;
  136. return invoke (info, asynchronously);
  137. }
  138. //==============================================================================
  139. ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command)
  140. : commandID (command),
  141. commandFlags (0),
  142. invocationMethod (direct),
  143. originatingComponent (nullptr),
  144. isKeyDown (false),
  145. millisecsSinceKeyPressed (0)
  146. {
  147. }
  148. } // namespace juce