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.

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