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.

286 lines
9.5KB

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