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.

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