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.

292 lines
9.7KB

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