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_ComponentBoundsConstrainer.cpp 10KB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. ComponentBoundsConstrainer::ComponentBoundsConstrainer() noexcept
  18. : minW (0), maxW (0x3fffffff),
  19. minH (0), maxH (0x3fffffff),
  20. minOffTop (0),
  21. minOffLeft (0),
  22. minOffBottom (0),
  23. minOffRight (0),
  24. aspectRatio (0.0)
  25. {
  26. }
  27. ComponentBoundsConstrainer::~ComponentBoundsConstrainer()
  28. {
  29. }
  30. //==============================================================================
  31. void ComponentBoundsConstrainer::setMinimumWidth (const int minimumWidth) noexcept { minW = minimumWidth; }
  32. void ComponentBoundsConstrainer::setMaximumWidth (const int maximumWidth) noexcept { maxW = maximumWidth; }
  33. void ComponentBoundsConstrainer::setMinimumHeight (const int minimumHeight) noexcept { minH = minimumHeight; }
  34. void ComponentBoundsConstrainer::setMaximumHeight (const int maximumHeight) noexcept { maxH = maximumHeight; }
  35. void ComponentBoundsConstrainer::setMinimumSize (const int minimumWidth, const int minimumHeight) noexcept
  36. {
  37. jassert (maxW >= minimumWidth);
  38. jassert (maxH >= minimumHeight);
  39. jassert (minimumWidth > 0 && minimumHeight > 0);
  40. minW = minimumWidth;
  41. minH = minimumHeight;
  42. if (minW > maxW) maxW = minW;
  43. if (minH > maxH) maxH = minH;
  44. }
  45. void ComponentBoundsConstrainer::setMaximumSize (const int maximumWidth, const int maximumHeight) noexcept
  46. {
  47. jassert (maximumWidth >= minW);
  48. jassert (maximumHeight >= minH);
  49. jassert (maximumWidth > 0 && maximumHeight > 0);
  50. maxW = jmax (minW, maximumWidth);
  51. maxH = jmax (minH, maximumHeight);
  52. }
  53. void ComponentBoundsConstrainer::setSizeLimits (const int minimumWidth,
  54. const int minimumHeight,
  55. const int maximumWidth,
  56. const int maximumHeight) noexcept
  57. {
  58. jassert (maximumWidth >= minimumWidth);
  59. jassert (maximumHeight >= minimumHeight);
  60. jassert (maximumWidth > 0 && maximumHeight > 0);
  61. jassert (minimumWidth > 0 && minimumHeight > 0);
  62. minW = jmax (0, minimumWidth);
  63. minH = jmax (0, minimumHeight);
  64. maxW = jmax (minW, maximumWidth);
  65. maxH = jmax (minH, maximumHeight);
  66. }
  67. void ComponentBoundsConstrainer::setMinimumOnscreenAmounts (const int minimumWhenOffTheTop,
  68. const int minimumWhenOffTheLeft,
  69. const int minimumWhenOffTheBottom,
  70. const int minimumWhenOffTheRight) noexcept
  71. {
  72. minOffTop = minimumWhenOffTheTop;
  73. minOffLeft = minimumWhenOffTheLeft;
  74. minOffBottom = minimumWhenOffTheBottom;
  75. minOffRight = minimumWhenOffTheRight;
  76. }
  77. void ComponentBoundsConstrainer::setFixedAspectRatio (const double widthOverHeight) noexcept
  78. {
  79. aspectRatio = jmax (0.0, widthOverHeight);
  80. }
  81. double ComponentBoundsConstrainer::getFixedAspectRatio() const noexcept
  82. {
  83. return aspectRatio;
  84. }
  85. void ComponentBoundsConstrainer::setBoundsForComponent (Component* const component,
  86. const Rectangle<int>& targetBounds,
  87. const bool isStretchingTop,
  88. const bool isStretchingLeft,
  89. const bool isStretchingBottom,
  90. const bool isStretchingRight)
  91. {
  92. jassert (component != nullptr);
  93. Rectangle<int> limits, bounds (targetBounds);
  94. BorderSize<int> border;
  95. if (Component* const parent = component->getParentComponent())
  96. {
  97. limits.setSize (parent->getWidth(), parent->getHeight());
  98. }
  99. else
  100. {
  101. if (ComponentPeer* const peer = component->getPeer())
  102. border = peer->getFrameSize();
  103. limits = Desktop::getInstance().getDisplays().getDisplayContaining (bounds.getCentre()).userArea;
  104. }
  105. border.addTo (bounds);
  106. checkBounds (bounds,
  107. border.addedTo (component->getBounds()), limits,
  108. isStretchingTop, isStretchingLeft,
  109. isStretchingBottom, isStretchingRight);
  110. border.subtractFrom (bounds);
  111. applyBoundsToComponent (component, bounds);
  112. }
  113. void ComponentBoundsConstrainer::checkComponentBounds (Component* component)
  114. {
  115. setBoundsForComponent (component, component->getBounds(),
  116. false, false, false, false);
  117. }
  118. void ComponentBoundsConstrainer::applyBoundsToComponent (Component* component,
  119. const Rectangle<int>& bounds)
  120. {
  121. if (Component::Positioner* const positioner = component->getPositioner())
  122. positioner->applyNewBounds (bounds);
  123. else
  124. component->setBounds (bounds);
  125. }
  126. //==============================================================================
  127. void ComponentBoundsConstrainer::resizeStart()
  128. {
  129. }
  130. void ComponentBoundsConstrainer::resizeEnd()
  131. {
  132. }
  133. //==============================================================================
  134. void ComponentBoundsConstrainer::checkBounds (Rectangle<int>& bounds,
  135. const Rectangle<int>& old,
  136. const Rectangle<int>& limits,
  137. const bool isStretchingTop,
  138. const bool isStretchingLeft,
  139. const bool isStretchingBottom,
  140. const bool isStretchingRight)
  141. {
  142. if (isStretchingLeft)
  143. bounds.setLeft (jlimit (old.getRight() - maxW, old.getRight() - minW, bounds.getX()));
  144. else
  145. bounds.setWidth (jlimit (minW, maxW, bounds.getWidth()));
  146. if (isStretchingTop)
  147. bounds.setTop (jlimit (old.getBottom() - maxH, old.getBottom() - minH, bounds.getY()));
  148. else
  149. bounds.setHeight (jlimit (minH, maxH, bounds.getHeight()));
  150. if (bounds.isEmpty())
  151. return;
  152. if (minOffTop > 0)
  153. {
  154. const int limit = limits.getY() + jmin (minOffTop - bounds.getHeight(), 0);
  155. if (bounds.getY() < limit)
  156. {
  157. if (isStretchingTop)
  158. bounds.setTop (limits.getY());
  159. else
  160. bounds.setY (limit);
  161. }
  162. }
  163. if (minOffLeft > 0)
  164. {
  165. const int limit = limits.getX() + jmin (minOffLeft - bounds.getWidth(), 0);
  166. if (bounds.getX() < limit)
  167. {
  168. if (isStretchingLeft)
  169. bounds.setLeft (limits.getX());
  170. else
  171. bounds.setX (limit);
  172. }
  173. }
  174. if (minOffBottom > 0)
  175. {
  176. const int limit = limits.getBottom() - jmin (minOffBottom, bounds.getHeight());
  177. if (bounds.getY() > limit)
  178. {
  179. if (isStretchingBottom)
  180. bounds.setBottom (limits.getBottom());
  181. else
  182. bounds.setY (limit);
  183. }
  184. }
  185. if (minOffRight > 0)
  186. {
  187. const int limit = limits.getRight() - jmin (minOffRight, bounds.getWidth());
  188. if (bounds.getX() > limit)
  189. {
  190. if (isStretchingRight)
  191. bounds.setRight (limits.getRight());
  192. else
  193. bounds.setX (limit);
  194. }
  195. }
  196. // constrain the aspect ratio if one has been specified..
  197. if (aspectRatio > 0.0)
  198. {
  199. bool adjustWidth;
  200. if ((isStretchingTop || isStretchingBottom) && ! (isStretchingLeft || isStretchingRight))
  201. {
  202. adjustWidth = true;
  203. }
  204. else if ((isStretchingLeft || isStretchingRight) && ! (isStretchingTop || isStretchingBottom))
  205. {
  206. adjustWidth = false;
  207. }
  208. else
  209. {
  210. const double oldRatio = (old.getHeight() > 0) ? std::abs (old.getWidth() / (double) old.getHeight()) : 0.0;
  211. const double newRatio = std::abs (bounds.getWidth() / (double) bounds.getHeight());
  212. adjustWidth = (oldRatio > newRatio);
  213. }
  214. if (adjustWidth)
  215. {
  216. bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio));
  217. if (bounds.getWidth() > maxW || bounds.getWidth() < minW)
  218. {
  219. bounds.setWidth (jlimit (minW, maxW, bounds.getWidth()));
  220. bounds.setHeight (roundToInt (bounds.getWidth() / aspectRatio));
  221. }
  222. }
  223. else
  224. {
  225. bounds.setHeight (roundToInt (bounds.getWidth() / aspectRatio));
  226. if (bounds.getHeight() > maxH || bounds.getHeight() < minH)
  227. {
  228. bounds.setHeight (jlimit (minH, maxH, bounds.getHeight()));
  229. bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio));
  230. }
  231. }
  232. if ((isStretchingTop || isStretchingBottom) && ! (isStretchingLeft || isStretchingRight))
  233. {
  234. bounds.setX (old.getX() + (old.getWidth() - bounds.getWidth()) / 2);
  235. }
  236. else if ((isStretchingLeft || isStretchingRight) && ! (isStretchingTop || isStretchingBottom))
  237. {
  238. bounds.setY (old.getY() + (old.getHeight() - bounds.getHeight()) / 2);
  239. }
  240. else
  241. {
  242. if (isStretchingLeft)
  243. bounds.setX (old.getRight() - bounds.getWidth());
  244. if (isStretchingTop)
  245. bounds.setY (old.getBottom() - bounds.getHeight());
  246. }
  247. }
  248. jassert (! bounds.isEmpty());
  249. }