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.

299 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. ComponentBoundsConstrainer::ComponentBoundsConstrainer() noexcept {}
  16. ComponentBoundsConstrainer::~ComponentBoundsConstrainer() {}
  17. //==============================================================================
  18. void ComponentBoundsConstrainer::setMinimumWidth (int minimumWidth) noexcept { minW = minimumWidth; }
  19. void ComponentBoundsConstrainer::setMaximumWidth (int maximumWidth) noexcept { maxW = maximumWidth; }
  20. void ComponentBoundsConstrainer::setMinimumHeight (int minimumHeight) noexcept { minH = minimumHeight; }
  21. void ComponentBoundsConstrainer::setMaximumHeight (int maximumHeight) noexcept { maxH = maximumHeight; }
  22. void ComponentBoundsConstrainer::setMinimumSize (int minimumWidth, int minimumHeight) noexcept
  23. {
  24. jassert (maxW >= minimumWidth);
  25. jassert (maxH >= minimumHeight);
  26. jassert (minimumWidth > 0 && minimumHeight > 0);
  27. minW = minimumWidth;
  28. minH = minimumHeight;
  29. if (minW > maxW) maxW = minW;
  30. if (minH > maxH) maxH = minH;
  31. }
  32. void ComponentBoundsConstrainer::setMaximumSize (int maximumWidth, int maximumHeight) noexcept
  33. {
  34. jassert (maximumWidth >= minW);
  35. jassert (maximumHeight >= minH);
  36. jassert (maximumWidth > 0 && maximumHeight > 0);
  37. maxW = jmax (minW, maximumWidth);
  38. maxH = jmax (minH, maximumHeight);
  39. }
  40. void ComponentBoundsConstrainer::setSizeLimits (int minimumWidth,
  41. int minimumHeight,
  42. int maximumWidth,
  43. int maximumHeight) noexcept
  44. {
  45. jassert (maximumWidth >= minimumWidth);
  46. jassert (maximumHeight >= minimumHeight);
  47. jassert (maximumWidth > 0 && maximumHeight > 0);
  48. jassert (minimumWidth > 0 && minimumHeight > 0);
  49. minW = jmax (0, minimumWidth);
  50. minH = jmax (0, minimumHeight);
  51. maxW = jmax (minW, maximumWidth);
  52. maxH = jmax (minH, maximumHeight);
  53. }
  54. void ComponentBoundsConstrainer::setMinimumOnscreenAmounts (int minimumWhenOffTheTop,
  55. int minimumWhenOffTheLeft,
  56. int minimumWhenOffTheBottom,
  57. int minimumWhenOffTheRight) noexcept
  58. {
  59. minOffTop = minimumWhenOffTheTop;
  60. minOffLeft = minimumWhenOffTheLeft;
  61. minOffBottom = minimumWhenOffTheBottom;
  62. minOffRight = minimumWhenOffTheRight;
  63. }
  64. void ComponentBoundsConstrainer::setFixedAspectRatio (double widthOverHeight) noexcept
  65. {
  66. aspectRatio = jmax (0.0, widthOverHeight);
  67. }
  68. double ComponentBoundsConstrainer::getFixedAspectRatio() const noexcept
  69. {
  70. return aspectRatio;
  71. }
  72. void ComponentBoundsConstrainer::setBoundsForComponent (Component* component,
  73. Rectangle<int> targetBounds,
  74. bool isStretchingTop,
  75. bool isStretchingLeft,
  76. bool isStretchingBottom,
  77. bool isStretchingRight)
  78. {
  79. jassert (component != nullptr);
  80. auto bounds = targetBounds;
  81. auto limits = [&]() -> Rectangle<int>
  82. {
  83. if (auto* parent = component->getParentComponent())
  84. return { parent->getWidth(), parent->getHeight() };
  85. const auto globalBounds = component->localAreaToGlobal (targetBounds - component->getPosition());
  86. if (auto* display = Desktop::getInstance().getDisplays().getDisplayForPoint (globalBounds.getCentre()))
  87. return component->getLocalArea (nullptr, display->userArea) + component->getPosition();
  88. const auto max = std::numeric_limits<int>::max();
  89. return { max, max };
  90. }();
  91. auto border = [&]() -> BorderSize<int>
  92. {
  93. if (component->getParentComponent() == nullptr)
  94. if (auto* peer = component->getPeer())
  95. if (const auto frameSize = peer->getFrameSizeIfPresent())
  96. return *frameSize;
  97. return {};
  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