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.

339 lines
11KB

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