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

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