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_RelativeCoordinatePositioner.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. struct MarkerListScope : public Expression::Scope
  22. {
  23. MarkerListScope (Component& comp) : component (comp) {}
  24. // Suppress a VS2013 compiler warning
  25. MarkerListScope& operator= (const MarkerListScope&) = delete;
  26. Expression getSymbolValue (const String& symbol) const override
  27. {
  28. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  29. {
  30. case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
  31. case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
  32. default: break;
  33. }
  34. MarkerList* list;
  35. if (auto* marker = findMarker (component, symbol, list))
  36. return Expression (marker->position.getExpression().evaluate (*this));
  37. return Expression::Scope::getSymbolValue (symbol);
  38. }
  39. void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
  40. {
  41. if (scopeName == RelativeCoordinate::Strings::parent)
  42. {
  43. if (auto* parent = component.getParentComponent())
  44. {
  45. visitor.visit (MarkerListScope (*parent));
  46. return;
  47. }
  48. }
  49. Expression::Scope::visitRelativeScope (scopeName, visitor);
  50. }
  51. String getScopeUID() const override
  52. {
  53. return String::toHexString ((pointer_sized_int) (void*) &component) + "m";
  54. }
  55. static const MarkerList::Marker* findMarker (Component& component, const String& name, MarkerList*& list)
  56. {
  57. const MarkerList::Marker* marker = nullptr;
  58. list = component.getMarkers (true);
  59. if (list != nullptr)
  60. marker = list->getMarker (name);
  61. if (marker == nullptr)
  62. {
  63. list = component.getMarkers (false);
  64. if (list != nullptr)
  65. marker = list->getMarker (name);
  66. }
  67. return marker;
  68. }
  69. Component& component;
  70. };
  71. //==============================================================================
  72. RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& comp)
  73. : component (comp)
  74. {
  75. }
  76. Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
  77. {
  78. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  79. {
  80. case RelativeCoordinate::StandardStrings::x:
  81. case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
  82. case RelativeCoordinate::StandardStrings::y:
  83. case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
  84. case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
  85. case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
  86. case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
  87. case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
  88. default: break;
  89. }
  90. if (Component* const parent = component.getParentComponent())
  91. {
  92. MarkerList* list;
  93. if (const MarkerList::Marker* const marker = MarkerListScope::findMarker (*parent, symbol, list))
  94. {
  95. MarkerListScope scope (*parent);
  96. return Expression (marker->position.getExpression().evaluate (scope));
  97. }
  98. }
  99. return Expression::Scope::getSymbolValue (symbol);
  100. }
  101. void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
  102. {
  103. if (auto* targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  104. ? component.getParentComponent()
  105. : findSiblingComponent (scopeName))
  106. visitor.visit (ComponentScope (*targetComp));
  107. else
  108. Expression::Scope::visitRelativeScope (scopeName, visitor);
  109. }
  110. String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
  111. {
  112. return String::toHexString ((pointer_sized_int) (void*) &component);
  113. }
  114. Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
  115. {
  116. if (Component* const parent = component.getParentComponent())
  117. return parent->findChildWithID (componentID);
  118. return nullptr;
  119. }
  120. //==============================================================================
  121. class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
  122. {
  123. public:
  124. DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& p, bool& result)
  125. : ComponentScope (comp), positioner (p), ok (result)
  126. {
  127. }
  128. Expression getSymbolValue (const String& symbol) const override
  129. {
  130. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  131. {
  132. case RelativeCoordinate::StandardStrings::x:
  133. case RelativeCoordinate::StandardStrings::left:
  134. case RelativeCoordinate::StandardStrings::y:
  135. case RelativeCoordinate::StandardStrings::top:
  136. case RelativeCoordinate::StandardStrings::width:
  137. case RelativeCoordinate::StandardStrings::height:
  138. case RelativeCoordinate::StandardStrings::right:
  139. case RelativeCoordinate::StandardStrings::bottom:
  140. positioner.registerComponentListener (component);
  141. break;
  142. default:
  143. if (Component* const parent = component.getParentComponent())
  144. {
  145. MarkerList* list;
  146. if (MarkerListScope::findMarker (*parent, symbol, list) != nullptr)
  147. {
  148. positioner.registerMarkerListListener (list);
  149. }
  150. else
  151. {
  152. // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
  153. positioner.registerMarkerListListener (parent->getMarkers (true));
  154. positioner.registerMarkerListListener (parent->getMarkers (false));
  155. ok = false;
  156. }
  157. }
  158. break;
  159. }
  160. return ComponentScope::getSymbolValue (symbol);
  161. }
  162. void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
  163. {
  164. if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  165. ? component.getParentComponent()
  166. : findSiblingComponent (scopeName))
  167. {
  168. visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
  169. }
  170. else
  171. {
  172. // The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
  173. if (Component* const parent = component.getParentComponent())
  174. positioner.registerComponentListener (*parent);
  175. positioner.registerComponentListener (component);
  176. ok = false;
  177. }
  178. }
  179. private:
  180. RelativeCoordinatePositionerBase& positioner;
  181. bool& ok;
  182. };
  183. //==============================================================================
  184. RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& comp)
  185. : Component::Positioner (comp), registeredOk (false)
  186. {
  187. }
  188. RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
  189. {
  190. unregisterListeners();
  191. }
  192. void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  193. {
  194. apply();
  195. }
  196. void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Component&)
  197. {
  198. apply();
  199. }
  200. void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed)
  201. {
  202. if (getComponent().getParentComponent() == &changed && ! registeredOk)
  203. apply();
  204. }
  205. void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& comp)
  206. {
  207. jassert (sourceComponents.contains (&comp));
  208. sourceComponents.removeFirstMatchingValue (&comp);
  209. registeredOk = false;
  210. }
  211. void RelativeCoordinatePositionerBase::markersChanged (MarkerList*)
  212. {
  213. apply();
  214. }
  215. void RelativeCoordinatePositionerBase::markerListBeingDeleted (MarkerList* markerList)
  216. {
  217. jassert (sourceMarkerLists.contains (markerList));
  218. sourceMarkerLists.removeFirstMatchingValue (markerList);
  219. }
  220. void RelativeCoordinatePositionerBase::apply()
  221. {
  222. if (! registeredOk)
  223. {
  224. unregisterListeners();
  225. registeredOk = registerCoordinates();
  226. }
  227. applyToComponentBounds();
  228. }
  229. bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
  230. {
  231. bool ok = true;
  232. DependencyFinderScope finderScope (getComponent(), *this, ok);
  233. coord.getExpression().evaluate (finderScope);
  234. return ok;
  235. }
  236. bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
  237. {
  238. const bool ok = addCoordinate (point.x);
  239. return addCoordinate (point.y) && ok;
  240. }
  241. void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
  242. {
  243. if (! sourceComponents.contains (&comp))
  244. {
  245. comp.addComponentListener (this);
  246. sourceComponents.add (&comp);
  247. }
  248. }
  249. void RelativeCoordinatePositionerBase::registerMarkerListListener (MarkerList* const list)
  250. {
  251. if (list != nullptr && ! sourceMarkerLists.contains (list))
  252. {
  253. list->addListener (this);
  254. sourceMarkerLists.add (list);
  255. }
  256. }
  257. void RelativeCoordinatePositionerBase::unregisterListeners()
  258. {
  259. for (int i = sourceComponents.size(); --i >= 0;)
  260. sourceComponents.getUnchecked(i)->removeComponentListener (this);
  261. for (int i = sourceMarkerLists.size(); --i >= 0;)
  262. sourceMarkerLists.getUnchecked(i)->removeListener (this);
  263. sourceComponents.clear();
  264. sourceMarkerLists.clear();
  265. }
  266. } // namespace juce