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.

338 lines
11KB

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