juce_RelativeCoordinatePositioner.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. class MarkerListScope : public Expression::Scope
  18. {
  19. public:
  20. MarkerListScope (Component& comp) : component (comp) {}
  21. Expression getSymbolValue (const String& symbol) const override
  22. {
  23. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  24. {
  25. case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
  26. case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
  27. default: break;
  28. }
  29. MarkerList* list;
  30. if (const MarkerList::Marker* const marker = findMarker (component, symbol, list))
  31. return Expression (marker->position.getExpression().evaluate (*this));
  32. return Expression::Scope::getSymbolValue (symbol);
  33. }
  34. void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
  35. {
  36. if (scopeName == RelativeCoordinate::Strings::parent)
  37. {
  38. if (Component* const parent = component.getParentComponent())
  39. {
  40. visitor.visit (MarkerListScope (*parent));
  41. return;
  42. }
  43. }
  44. Expression::Scope::visitRelativeScope (scopeName, visitor);
  45. }
  46. String getScopeUID() const override
  47. {
  48. return String::toHexString ((pointer_sized_int) (void*) &component) + "m";
  49. }
  50. static const MarkerList::Marker* findMarker (Component& component, const String& name, MarkerList*& list)
  51. {
  52. const MarkerList::Marker* marker = nullptr;
  53. list = component.getMarkers (true);
  54. if (list != nullptr)
  55. marker = list->getMarker (name);
  56. if (marker == nullptr)
  57. {
  58. list = component.getMarkers (false);
  59. if (list != nullptr)
  60. marker = list->getMarker (name);
  61. }
  62. return marker;
  63. }
  64. private:
  65. Component& component;
  66. JUCE_DECLARE_NON_COPYABLE (MarkerListScope)
  67. };
  68. //==============================================================================
  69. RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& comp)
  70. : component (comp)
  71. {
  72. }
  73. Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
  74. {
  75. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  76. {
  77. case RelativeCoordinate::StandardStrings::x:
  78. case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
  79. case RelativeCoordinate::StandardStrings::y:
  80. case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
  81. case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
  82. case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
  83. case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
  84. case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
  85. default: break;
  86. }
  87. if (Component* const parent = component.getParentComponent())
  88. {
  89. MarkerList* list;
  90. if (const MarkerList::Marker* const marker = MarkerListScope::findMarker (*parent, symbol, list))
  91. {
  92. MarkerListScope scope (*parent);
  93. return Expression (marker->position.getExpression().evaluate (scope));
  94. }
  95. }
  96. return Expression::Scope::getSymbolValue (symbol);
  97. }
  98. void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
  99. {
  100. if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  101. ? component.getParentComponent()
  102. : findSiblingComponent (scopeName))
  103. visitor.visit (ComponentScope (*targetComp));
  104. else
  105. Expression::Scope::visitRelativeScope (scopeName, visitor);
  106. }
  107. String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
  108. {
  109. return String::toHexString ((pointer_sized_int) (void*) &component);
  110. }
  111. Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
  112. {
  113. if (Component* const parent = component.getParentComponent())
  114. return parent->findChildWithID (componentID);
  115. return nullptr;
  116. }
  117. //==============================================================================
  118. class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
  119. {
  120. public:
  121. DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& p, bool& result)
  122. : ComponentScope (comp), positioner (p), ok (result)
  123. {
  124. }
  125. Expression getSymbolValue (const String& symbol) const override
  126. {
  127. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  128. {
  129. case RelativeCoordinate::StandardStrings::x:
  130. case RelativeCoordinate::StandardStrings::left:
  131. case RelativeCoordinate::StandardStrings::y:
  132. case RelativeCoordinate::StandardStrings::top:
  133. case RelativeCoordinate::StandardStrings::width:
  134. case RelativeCoordinate::StandardStrings::height:
  135. case RelativeCoordinate::StandardStrings::right:
  136. case RelativeCoordinate::StandardStrings::bottom:
  137. positioner.registerComponentListener (component);
  138. break;
  139. default:
  140. if (Component* const parent = component.getParentComponent())
  141. {
  142. MarkerList* list;
  143. if (MarkerListScope::findMarker (*parent, symbol, list) != nullptr)
  144. {
  145. positioner.registerMarkerListListener (list);
  146. }
  147. else
  148. {
  149. // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
  150. positioner.registerMarkerListListener (parent->getMarkers (true));
  151. positioner.registerMarkerListListener (parent->getMarkers (false));
  152. ok = false;
  153. }
  154. }
  155. break;
  156. }
  157. return ComponentScope::getSymbolValue (symbol);
  158. }
  159. void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
  160. {
  161. if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
  162. ? component.getParentComponent()
  163. : findSiblingComponent (scopeName))
  164. {
  165. visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
  166. }
  167. else
  168. {
  169. // The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
  170. if (Component* const parent = component.getParentComponent())
  171. positioner.registerComponentListener (*parent);
  172. positioner.registerComponentListener (component);
  173. ok = false;
  174. }
  175. }
  176. private:
  177. RelativeCoordinatePositionerBase& positioner;
  178. bool& ok;
  179. JUCE_DECLARE_NON_COPYABLE (DependencyFinderScope)
  180. };
  181. //==============================================================================
  182. RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& comp)
  183. : Component::Positioner (comp), registeredOk (false)
  184. {
  185. }
  186. RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
  187. {
  188. unregisterListeners();
  189. }
  190. void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  191. {
  192. apply();
  193. }
  194. void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Component&)
  195. {
  196. apply();
  197. }
  198. void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed)
  199. {
  200. if (getComponent().getParentComponent() == &changed && ! registeredOk)
  201. apply();
  202. }
  203. void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& comp)
  204. {
  205. jassert (sourceComponents.contains (&comp));
  206. sourceComponents.removeFirstMatchingValue (&comp);
  207. registeredOk = false;
  208. }
  209. void RelativeCoordinatePositionerBase::markersChanged (MarkerList*)
  210. {
  211. apply();
  212. }
  213. void RelativeCoordinatePositionerBase::markerListBeingDeleted (MarkerList* markerList)
  214. {
  215. jassert (sourceMarkerLists.contains (markerList));
  216. sourceMarkerLists.removeFirstMatchingValue (markerList);
  217. }
  218. void RelativeCoordinatePositionerBase::apply()
  219. {
  220. if (! registeredOk)
  221. {
  222. unregisterListeners();
  223. registeredOk = registerCoordinates();
  224. }
  225. applyToComponentBounds();
  226. }
  227. bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
  228. {
  229. bool ok = true;
  230. DependencyFinderScope finderScope (getComponent(), *this, ok);
  231. coord.getExpression().evaluate (finderScope);
  232. return ok;
  233. }
  234. bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
  235. {
  236. const bool ok = addCoordinate (point.x);
  237. return addCoordinate (point.y) && ok;
  238. }
  239. void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
  240. {
  241. if (! sourceComponents.contains (&comp))
  242. {
  243. comp.addComponentListener (this);
  244. sourceComponents.add (&comp);
  245. }
  246. }
  247. void RelativeCoordinatePositionerBase::registerMarkerListListener (MarkerList* const list)
  248. {
  249. if (list != nullptr && ! sourceMarkerLists.contains (list))
  250. {
  251. list->addListener (this);
  252. sourceMarkerLists.add (list);
  253. }
  254. }
  255. void RelativeCoordinatePositionerBase::unregisterListeners()
  256. {
  257. for (int i = sourceComponents.size(); --i >= 0;)
  258. sourceComponents.getUnchecked(i)->removeComponentListener (this);
  259. for (int i = sourceMarkerLists.size(); --i >= 0;)
  260. sourceMarkerLists.getUnchecked(i)->removeListener (this);
  261. sourceComponents.clear();
  262. sourceMarkerLists.clear();
  263. }