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.

344 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. class MarkerListScope : public Expression::Scope
  21. {
  22. public:
  23. MarkerListScope (Component& component_) : component (component_) {}
  24. Expression getSymbolValue (const String& symbol) const
  25. {
  26. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  27. {
  28. case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
  29. case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
  30. default: break;
  31. }
  32. MarkerList* list;
  33. const MarkerList::Marker* const marker = findMarker (component, symbol, list);
  34. if (marker != nullptr)
  35. return Expression (marker->position.getExpression().evaluate (*this));
  36. return Expression::Scope::getSymbolValue (symbol);
  37. }
  38. void visitRelativeScope (const String& scopeName, Visitor& visitor) const
  39. {
  40. if (scopeName == RelativeCoordinate::Strings::parent)
  41. {
  42. Component* const parent = component.getParentComponent();
  43. if (parent != nullptr)
  44. {
  45. visitor.visit (MarkerListScope (*parent));
  46. return;
  47. }
  48. }
  49. Expression::Scope::visitRelativeScope (scopeName, visitor);
  50. }
  51. String getScopeUID() const
  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. private:
  70. Component& component;
  71. JUCE_DECLARE_NON_COPYABLE (MarkerListScope);
  72. };
  73. //==============================================================================
  74. RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& component_)
  75. : component (component_)
  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. default: break;
  91. }
  92. Component* const parent = component.getParentComponent();
  93. if (parent != nullptr)
  94. {
  95. MarkerList* list;
  96. const MarkerList::Marker* const marker = MarkerListScope::findMarker (*parent, symbol, list);
  97. if (marker != nullptr)
  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. Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  108. ? component.getParentComponent()
  109. : findSiblingComponent (scopeName);
  110. if (targetComp != nullptr)
  111. visitor.visit (ComponentScope (*targetComp));
  112. else
  113. Expression::Scope::visitRelativeScope (scopeName, visitor);
  114. }
  115. String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
  116. {
  117. return String::toHexString ((pointer_sized_int) (void*) &component);
  118. }
  119. Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
  120. {
  121. Component* const parent = component.getParentComponent();
  122. return parent != nullptr ? parent->findChildWithID (componentID)
  123. : nullptr;
  124. }
  125. //==============================================================================
  126. class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
  127. {
  128. public:
  129. DependencyFinderScope (Component& component_, RelativeCoordinatePositionerBase& positioner_, bool& ok_)
  130. : ComponentScope (component_), positioner (positioner_), ok (ok_)
  131. {
  132. }
  133. Expression getSymbolValue (const String& symbol) const
  134. {
  135. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  136. {
  137. case RelativeCoordinate::StandardStrings::x:
  138. case RelativeCoordinate::StandardStrings::left:
  139. case RelativeCoordinate::StandardStrings::y:
  140. case RelativeCoordinate::StandardStrings::top:
  141. case RelativeCoordinate::StandardStrings::width:
  142. case RelativeCoordinate::StandardStrings::height:
  143. case RelativeCoordinate::StandardStrings::right:
  144. case RelativeCoordinate::StandardStrings::bottom:
  145. positioner.registerComponentListener (component);
  146. break;
  147. default:
  148. {
  149. Component* const parent = component.getParentComponent();
  150. if (parent != nullptr)
  151. {
  152. MarkerList* list;
  153. const MarkerList::Marker* marker = MarkerListScope::findMarker (*parent, symbol, list);
  154. if (marker != nullptr)
  155. {
  156. positioner.registerMarkerListListener (list);
  157. }
  158. else
  159. {
  160. // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
  161. positioner.registerMarkerListListener (parent->getMarkers (true));
  162. positioner.registerMarkerListListener (parent->getMarkers (false));
  163. ok = false;
  164. }
  165. }
  166. }
  167. break;
  168. }
  169. return ComponentScope::getSymbolValue (symbol);
  170. }
  171. void visitRelativeScope (const String& scopeName, Visitor& visitor) const
  172. {
  173. Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  174. ? component.getParentComponent()
  175. : findSiblingComponent (scopeName);
  176. if (targetComp != nullptr)
  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. Component* const parent = component.getParentComponent();
  184. if (parent != nullptr)
  185. positioner.registerComponentListener (*parent);
  186. positioner.registerComponentListener (component);
  187. ok = false;
  188. }
  189. }
  190. private:
  191. RelativeCoordinatePositionerBase& positioner;
  192. bool& ok;
  193. JUCE_DECLARE_NON_COPYABLE (DependencyFinderScope);
  194. };
  195. //==============================================================================
  196. RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& component_)
  197. : Component::Positioner (component_), registeredOk (false)
  198. {
  199. }
  200. RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
  201. {
  202. unregisterListeners();
  203. }
  204. void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  205. {
  206. apply();
  207. }
  208. void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Component&)
  209. {
  210. apply();
  211. }
  212. void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed)
  213. {
  214. if (getComponent().getParentComponent() == &changed && ! registeredOk)
  215. apply();
  216. }
  217. void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& comp)
  218. {
  219. jassert (sourceComponents.contains (&comp));
  220. sourceComponents.removeValue (&comp);
  221. registeredOk = false;
  222. }
  223. void RelativeCoordinatePositionerBase::markersChanged (MarkerList*)
  224. {
  225. apply();
  226. }
  227. void RelativeCoordinatePositionerBase::markerListBeingDeleted (MarkerList* markerList)
  228. {
  229. jassert (sourceMarkerLists.contains (markerList));
  230. sourceMarkerLists.removeValue (markerList);
  231. }
  232. void RelativeCoordinatePositionerBase::apply()
  233. {
  234. if (! registeredOk)
  235. {
  236. unregisterListeners();
  237. registeredOk = registerCoordinates();
  238. }
  239. applyToComponentBounds();
  240. }
  241. bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
  242. {
  243. bool ok = true;
  244. DependencyFinderScope finderScope (getComponent(), *this, ok);
  245. coord.getExpression().evaluate (finderScope);
  246. return ok;
  247. }
  248. bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
  249. {
  250. const bool ok = addCoordinate (point.x);
  251. return addCoordinate (point.y) && ok;
  252. }
  253. void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
  254. {
  255. if (! sourceComponents.contains (&comp))
  256. {
  257. comp.addComponentListener (this);
  258. sourceComponents.add (&comp);
  259. }
  260. }
  261. void RelativeCoordinatePositionerBase::registerMarkerListListener (MarkerList* const list)
  262. {
  263. if (list != nullptr && ! sourceMarkerLists.contains (list))
  264. {
  265. list->addListener (this);
  266. sourceMarkerLists.add (list);
  267. }
  268. }
  269. void RelativeCoordinatePositionerBase::unregisterListeners()
  270. {
  271. int i;
  272. for (i = sourceComponents.size(); --i >= 0;)
  273. sourceComponents.getUnchecked(i)->removeComponentListener (this);
  274. for (i = sourceMarkerLists.size(); --i >= 0;)
  275. sourceMarkerLists.getUnchecked(i)->removeListener (this);
  276. sourceComponents.clear();
  277. sourceMarkerLists.clear();
  278. }
  279. END_JUCE_NAMESPACE