juce_ComponentBoundsConstrainer.cpp 10 KB

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