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.

322 lines
11KB

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