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.

303 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. ComponentBoundsConstrainer::ComponentBoundsConstrainer() noexcept
  19. : minW (0), maxW (0x3fffffff),
  20. minH (0), maxH (0x3fffffff),
  21. minOffTop (0),
  22. minOffLeft (0),
  23. minOffBottom (0),
  24. minOffRight (0),
  25. aspectRatio (0.0)
  26. {
  27. }
  28. ComponentBoundsConstrainer::~ComponentBoundsConstrainer()
  29. {
  30. }
  31. //==============================================================================
  32. void ComponentBoundsConstrainer::setMinimumWidth (const int minimumWidth) noexcept { minW = minimumWidth; }
  33. void ComponentBoundsConstrainer::setMaximumWidth (const int maximumWidth) noexcept { maxW = maximumWidth; }
  34. void ComponentBoundsConstrainer::setMinimumHeight (const int minimumHeight) noexcept { minH = minimumHeight; }
  35. void ComponentBoundsConstrainer::setMaximumHeight (const int maximumHeight) noexcept { maxH = maximumHeight; }
  36. void ComponentBoundsConstrainer::setMinimumSize (const int minimumWidth, const int minimumHeight) noexcept
  37. {
  38. jassert (maxW >= minimumWidth);
  39. jassert (maxH >= minimumHeight);
  40. jassert (minimumWidth > 0 && minimumHeight > 0);
  41. minW = minimumWidth;
  42. minH = minimumHeight;
  43. if (minW > maxW) maxW = minW;
  44. if (minH > maxH) maxH = minH;
  45. }
  46. void ComponentBoundsConstrainer::setMaximumSize (const int maximumWidth, const int maximumHeight) noexcept
  47. {
  48. jassert (maximumWidth >= minW);
  49. jassert (maximumHeight >= minH);
  50. jassert (maximumWidth > 0 && maximumHeight > 0);
  51. maxW = jmax (minW, maximumWidth);
  52. maxH = jmax (minH, maximumHeight);
  53. }
  54. void ComponentBoundsConstrainer::setSizeLimits (const int minimumWidth,
  55. const int minimumHeight,
  56. const int maximumWidth,
  57. const int maximumHeight) noexcept
  58. {
  59. jassert (maximumWidth >= minimumWidth);
  60. jassert (maximumHeight >= minimumHeight);
  61. jassert (maximumWidth > 0 && maximumHeight > 0);
  62. jassert (minimumWidth > 0 && minimumHeight > 0);
  63. minW = jmax (0, minimumWidth);
  64. minH = jmax (0, minimumHeight);
  65. maxW = jmax (minW, maximumWidth);
  66. maxH = jmax (minH, maximumHeight);
  67. }
  68. void ComponentBoundsConstrainer::setMinimumOnscreenAmounts (const int minimumWhenOffTheTop,
  69. const int minimumWhenOffTheLeft,
  70. const int minimumWhenOffTheBottom,
  71. const int minimumWhenOffTheRight) noexcept
  72. {
  73. minOffTop = minimumWhenOffTheTop;
  74. minOffLeft = minimumWhenOffTheLeft;
  75. minOffBottom = minimumWhenOffTheBottom;
  76. minOffRight = minimumWhenOffTheRight;
  77. }
  78. void ComponentBoundsConstrainer::setFixedAspectRatio (const double widthOverHeight) noexcept
  79. {
  80. aspectRatio = jmax (0.0, widthOverHeight);
  81. }
  82. double ComponentBoundsConstrainer::getFixedAspectRatio() const noexcept
  83. {
  84. return aspectRatio;
  85. }
  86. void ComponentBoundsConstrainer::setBoundsForComponent (Component* const component,
  87. const Rectangle<int>& targetBounds,
  88. const bool isStretchingTop,
  89. const bool isStretchingLeft,
  90. const bool isStretchingBottom,
  91. const bool isStretchingRight)
  92. {
  93. jassert (component != nullptr);
  94. Rectangle<int> limits, bounds (targetBounds);
  95. BorderSize<int> border;
  96. if (Component* const parent = component->getParentComponent())
  97. {
  98. limits.setSize (parent->getWidth(), parent->getHeight());
  99. }
  100. else
  101. {
  102. if (ComponentPeer* const peer = component->getPeer())
  103. border = peer->getFrameSize();
  104. limits = Desktop::getInstance().getDisplays().getDisplayContaining (bounds.getCentre()).userArea;
  105. }
  106. border.addTo (bounds);
  107. checkBounds (bounds,
  108. border.addedTo (component->getBounds()), limits,
  109. isStretchingTop, isStretchingLeft,
  110. isStretchingBottom, isStretchingRight);
  111. border.subtractFrom (bounds);
  112. applyBoundsToComponent (component, bounds);
  113. }
  114. void ComponentBoundsConstrainer::checkComponentBounds (Component* component)
  115. {
  116. setBoundsForComponent (component, component->getBounds(),
  117. false, false, false, false);
  118. }
  119. void ComponentBoundsConstrainer::applyBoundsToComponent (Component* component,
  120. const Rectangle<int>& bounds)
  121. {
  122. if (Component::Positioner* const positioner = component->getPositioner())
  123. positioner->applyNewBounds (bounds);
  124. else
  125. component->setBounds (bounds);
  126. }
  127. //==============================================================================
  128. void ComponentBoundsConstrainer::resizeStart()
  129. {
  130. }
  131. void ComponentBoundsConstrainer::resizeEnd()
  132. {
  133. }
  134. //==============================================================================
  135. void ComponentBoundsConstrainer::checkBounds (Rectangle<int>& bounds,
  136. const Rectangle<int>& old,
  137. const Rectangle<int>& limits,
  138. const bool isStretchingTop,
  139. const bool isStretchingLeft,
  140. const bool isStretchingBottom,
  141. const bool isStretchingRight)
  142. {
  143. if (isStretchingLeft)
  144. bounds.setLeft (jlimit (old.getRight() - maxW, old.getRight() - minW, bounds.getX()));
  145. else
  146. bounds.setWidth (jlimit (minW, maxW, bounds.getWidth()));
  147. if (isStretchingTop)
  148. bounds.setTop (jlimit (old.getBottom() - maxH, old.getBottom() - minH, bounds.getY()));
  149. else
  150. bounds.setHeight (jlimit (minH, maxH, bounds.getHeight()));
  151. if (bounds.isEmpty())
  152. return;
  153. if (minOffTop > 0)
  154. {
  155. const int limit = limits.getY() + jmin (minOffTop - bounds.getHeight(), 0);
  156. if (bounds.getY() < limit)
  157. {
  158. if (isStretchingTop)
  159. bounds.setTop (limits.getY());
  160. else
  161. bounds.setY (limit);
  162. }
  163. }
  164. if (minOffLeft > 0)
  165. {
  166. const int limit = limits.getX() + jmin (minOffLeft - bounds.getWidth(), 0);
  167. if (bounds.getX() < limit)
  168. {
  169. if (isStretchingLeft)
  170. bounds.setLeft (limits.getX());
  171. else
  172. bounds.setX (limit);
  173. }
  174. }
  175. if (minOffBottom > 0)
  176. {
  177. const int limit = limits.getBottom() - jmin (minOffBottom, bounds.getHeight());
  178. if (bounds.getY() > limit)
  179. {
  180. if (isStretchingBottom)
  181. bounds.setBottom (limits.getBottom());
  182. else
  183. bounds.setY (limit);
  184. }
  185. }
  186. if (minOffRight > 0)
  187. {
  188. const int limit = limits.getRight() - jmin (minOffRight, bounds.getWidth());
  189. if (bounds.getX() > limit)
  190. {
  191. if (isStretchingRight)
  192. bounds.setRight (limits.getRight());
  193. else
  194. bounds.setX (limit);
  195. }
  196. }
  197. // constrain the aspect ratio if one has been specified..
  198. if (aspectRatio > 0.0)
  199. {
  200. bool adjustWidth;
  201. if ((isStretchingTop || isStretchingBottom) && ! (isStretchingLeft || isStretchingRight))
  202. {
  203. adjustWidth = true;
  204. }
  205. else if ((isStretchingLeft || isStretchingRight) && ! (isStretchingTop || isStretchingBottom))
  206. {
  207. adjustWidth = false;
  208. }
  209. else
  210. {
  211. const double oldRatio = (old.getHeight() > 0) ? std::abs (old.getWidth() / (double) old.getHeight()) : 0.0;
  212. const double newRatio = std::abs (bounds.getWidth() / (double) bounds.getHeight());
  213. adjustWidth = (oldRatio > newRatio);
  214. }
  215. if (adjustWidth)
  216. {
  217. bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio));
  218. if (bounds.getWidth() > maxW || bounds.getWidth() < minW)
  219. {
  220. bounds.setWidth (jlimit (minW, maxW, bounds.getWidth()));
  221. bounds.setHeight (roundToInt (bounds.getWidth() / aspectRatio));
  222. }
  223. }
  224. else
  225. {
  226. bounds.setHeight (roundToInt (bounds.getWidth() / aspectRatio));
  227. if (bounds.getHeight() > maxH || bounds.getHeight() < minH)
  228. {
  229. bounds.setHeight (jlimit (minH, maxH, bounds.getHeight()));
  230. bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio));
  231. }
  232. }
  233. if ((isStretchingTop || isStretchingBottom) && ! (isStretchingLeft || isStretchingRight))
  234. {
  235. bounds.setX (old.getX() + (old.getWidth() - bounds.getWidth()) / 2);
  236. }
  237. else if ((isStretchingLeft || isStretchingRight) && ! (isStretchingTop || isStretchingBottom))
  238. {
  239. bounds.setY (old.getY() + (old.getHeight() - bounds.getHeight()) / 2);
  240. }
  241. else
  242. {
  243. if (isStretchingLeft)
  244. bounds.setX (old.getRight() - bounds.getWidth());
  245. if (isStretchingTop)
  246. bounds.setY (old.getBottom() - bounds.getHeight());
  247. }
  248. }
  249. jassert (! bounds.isEmpty());
  250. }