Audio plugin host https://kx.studio/carla
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.

juce_RelativeRectangle.cpp 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. namespace RelativeRectangleHelpers
  21. {
  22. inline void skipComma (String::CharPointerType& s)
  23. {
  24. s.incrementToEndOfWhitespace();
  25. if (*s == ',')
  26. ++s;
  27. }
  28. static bool dependsOnSymbolsOtherThanThis (const Expression& e)
  29. {
  30. if (e.getType() == Expression::operatorType && e.getSymbolOrFunction() == ".")
  31. return true;
  32. if (e.getType() == Expression::symbolType)
  33. {
  34. switch (RelativeCoordinate::StandardStrings::getTypeOf (e.getSymbolOrFunction()))
  35. {
  36. case RelativeCoordinate::StandardStrings::x:
  37. case RelativeCoordinate::StandardStrings::y:
  38. case RelativeCoordinate::StandardStrings::left:
  39. case RelativeCoordinate::StandardStrings::right:
  40. case RelativeCoordinate::StandardStrings::top:
  41. case RelativeCoordinate::StandardStrings::bottom: return false;
  42. case RelativeCoordinate::StandardStrings::width:
  43. case RelativeCoordinate::StandardStrings::height:
  44. case RelativeCoordinate::StandardStrings::parent:
  45. case RelativeCoordinate::StandardStrings::unknown:
  46. default: break;
  47. }
  48. return true;
  49. }
  50. else
  51. {
  52. for (int i = e.getNumInputs(); --i >= 0;)
  53. if (dependsOnSymbolsOtherThanThis (e.getInput(i)))
  54. return true;
  55. }
  56. return false;
  57. }
  58. }
  59. //==============================================================================
  60. RelativeRectangle::RelativeRectangle()
  61. {
  62. }
  63. RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const RelativeCoordinate& right_,
  64. const RelativeCoordinate& top_, const RelativeCoordinate& bottom_)
  65. : left (left_), right (right_), top (top_), bottom (bottom_)
  66. {
  67. }
  68. RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect)
  69. : left (rect.getX()),
  70. right (Expression::symbol (RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())),
  71. top (rect.getY()),
  72. bottom (Expression::symbol (RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight()))
  73. {
  74. }
  75. RelativeRectangle::RelativeRectangle (const String& s)
  76. {
  77. String error;
  78. String::CharPointerType text (s.getCharPointer());
  79. left = RelativeCoordinate (Expression::parse (text, error));
  80. RelativeRectangleHelpers::skipComma (text);
  81. top = RelativeCoordinate (Expression::parse (text, error));
  82. RelativeRectangleHelpers::skipComma (text);
  83. right = RelativeCoordinate (Expression::parse (text, error));
  84. RelativeRectangleHelpers::skipComma (text);
  85. bottom = RelativeCoordinate (Expression::parse (text, error));
  86. }
  87. bool RelativeRectangle::operator== (const RelativeRectangle& other) const noexcept
  88. {
  89. return left == other.left && top == other.top && right == other.right && bottom == other.bottom;
  90. }
  91. bool RelativeRectangle::operator!= (const RelativeRectangle& other) const noexcept
  92. {
  93. return ! operator== (other);
  94. }
  95. //==============================================================================
  96. // An expression context that can evaluate expressions using "this"
  97. class RelativeRectangleLocalScope : public Expression::Scope
  98. {
  99. public:
  100. RelativeRectangleLocalScope (const RelativeRectangle& rect_) : rect (rect_) {}
  101. Expression getSymbolValue (const String& symbol) const
  102. {
  103. switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
  104. {
  105. case RelativeCoordinate::StandardStrings::x:
  106. case RelativeCoordinate::StandardStrings::left: return rect.left.getExpression();
  107. case RelativeCoordinate::StandardStrings::y:
  108. case RelativeCoordinate::StandardStrings::top: return rect.top.getExpression();
  109. case RelativeCoordinate::StandardStrings::right: return rect.right.getExpression();
  110. case RelativeCoordinate::StandardStrings::bottom: return rect.bottom.getExpression();
  111. case RelativeCoordinate::StandardStrings::width:
  112. case RelativeCoordinate::StandardStrings::height:
  113. case RelativeCoordinate::StandardStrings::parent:
  114. case RelativeCoordinate::StandardStrings::unknown:
  115. default: break;
  116. }
  117. return Expression::Scope::getSymbolValue (symbol);
  118. }
  119. private:
  120. const RelativeRectangle& rect;
  121. JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope)
  122. };
  123. const Rectangle<float> RelativeRectangle::resolve (const Expression::Scope* scope) const
  124. {
  125. if (scope == nullptr)
  126. {
  127. RelativeRectangleLocalScope defaultScope (*this);
  128. return resolve (&defaultScope);
  129. }
  130. else
  131. {
  132. const double l = left.resolve (scope);
  133. const double r = right.resolve (scope);
  134. const double t = top.resolve (scope);
  135. const double b = bottom.resolve (scope);
  136. return Rectangle<float> ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
  137. }
  138. }
  139. void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope)
  140. {
  141. left.moveToAbsolute (newPos.getX(), scope);
  142. right.moveToAbsolute (newPos.getRight(), scope);
  143. top.moveToAbsolute (newPos.getY(), scope);
  144. bottom.moveToAbsolute (newPos.getBottom(), scope);
  145. }
  146. bool RelativeRectangle::isDynamic() const
  147. {
  148. using namespace RelativeRectangleHelpers;
  149. return dependsOnSymbolsOtherThanThis (left.getExpression())
  150. || dependsOnSymbolsOtherThanThis (right.getExpression())
  151. || dependsOnSymbolsOtherThanThis (top.getExpression())
  152. || dependsOnSymbolsOtherThanThis (bottom.getExpression());
  153. }
  154. String RelativeRectangle::toString() const
  155. {
  156. return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
  157. }
  158. void RelativeRectangle::renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope)
  159. {
  160. left = left.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
  161. right = right.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
  162. top = top.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
  163. bottom = bottom.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
  164. }
  165. //==============================================================================
  166. class RelativeRectangleComponentPositioner : public RelativeCoordinatePositionerBase
  167. {
  168. public:
  169. RelativeRectangleComponentPositioner (Component& comp, const RelativeRectangle& r)
  170. : RelativeCoordinatePositionerBase (comp),
  171. rectangle (r)
  172. {
  173. }
  174. bool registerCoordinates() override
  175. {
  176. bool ok = addCoordinate (rectangle.left);
  177. ok = addCoordinate (rectangle.right) && ok;
  178. ok = addCoordinate (rectangle.top) && ok;
  179. ok = addCoordinate (rectangle.bottom) && ok;
  180. return ok;
  181. }
  182. bool isUsingRectangle (const RelativeRectangle& other) const noexcept
  183. {
  184. return rectangle == other;
  185. }
  186. void applyToComponentBounds() override
  187. {
  188. for (int i = 32; --i >= 0;)
  189. {
  190. ComponentScope scope (getComponent());
  191. const Rectangle<int> newBounds (rectangle.resolve (&scope).getSmallestIntegerContainer());
  192. if (newBounds == getComponent().getBounds())
  193. return;
  194. getComponent().setBounds (newBounds);
  195. }
  196. jassertfalse; // Seems to be a recursive reference!
  197. }
  198. void applyNewBounds (const Rectangle<int>& newBounds) override
  199. {
  200. if (newBounds != getComponent().getBounds())
  201. {
  202. ComponentScope scope (getComponent());
  203. rectangle.moveToAbsolute (newBounds.toFloat(), &scope);
  204. applyToComponentBounds();
  205. }
  206. }
  207. private:
  208. RelativeRectangle rectangle;
  209. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner)
  210. };
  211. void RelativeRectangle::applyToComponent (Component& component) const
  212. {
  213. if (isDynamic())
  214. {
  215. RelativeRectangleComponentPositioner* current = dynamic_cast<RelativeRectangleComponentPositioner*> (component.getPositioner());
  216. if (current == nullptr || ! current->isUsingRectangle (*this))
  217. {
  218. RelativeRectangleComponentPositioner* p = new RelativeRectangleComponentPositioner (component, *this);
  219. component.setPositioner (p);
  220. p->apply();
  221. }
  222. }
  223. else
  224. {
  225. component.setPositioner (nullptr);
  226. component.setBounds (resolve (nullptr).getSmallestIntegerContainer());
  227. }
  228. }
  229. } // namespace juce