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.

304 lines
10KB

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