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.

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