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.

540 lines
14KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. RectangleList::RectangleList() noexcept
  21. {
  22. }
  23. RectangleList::RectangleList (const Rectangle<int>& rect)
  24. {
  25. if (! rect.isEmpty())
  26. rects.add (rect);
  27. }
  28. RectangleList::RectangleList (const RectangleList& other)
  29. : rects (other.rects)
  30. {
  31. }
  32. RectangleList& RectangleList::operator= (const RectangleList& other)
  33. {
  34. rects = other.rects;
  35. return *this;
  36. }
  37. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  38. RectangleList::RectangleList (RectangleList&& other) noexcept
  39. : rects (static_cast <Array <Rectangle<int> >&&> (other.rects))
  40. {
  41. }
  42. RectangleList& RectangleList::operator= (RectangleList&& other) noexcept
  43. {
  44. rects = static_cast <Array <Rectangle<int> >&&> (other.rects);
  45. return *this;
  46. }
  47. #endif
  48. RectangleList::~RectangleList()
  49. {
  50. }
  51. //==============================================================================
  52. void RectangleList::clear()
  53. {
  54. rects.clearQuick();
  55. }
  56. Rectangle<int> RectangleList::getRectangle (const int index) const noexcept
  57. {
  58. if (isPositiveAndBelow (index, rects.size()))
  59. return rects.getReference (index);
  60. return Rectangle<int>();
  61. }
  62. bool RectangleList::isEmpty() const noexcept
  63. {
  64. return rects.size() == 0;
  65. }
  66. //==============================================================================
  67. RectangleList::Iterator::Iterator (const RectangleList& list) noexcept
  68. : current (nullptr),
  69. owner (list),
  70. index (list.rects.size())
  71. {
  72. }
  73. RectangleList::Iterator::~Iterator()
  74. {
  75. }
  76. bool RectangleList::Iterator::next() noexcept
  77. {
  78. if (--index >= 0)
  79. {
  80. current = & (owner.rects.getReference (index));
  81. return true;
  82. }
  83. return false;
  84. }
  85. //==============================================================================
  86. void RectangleList::add (const Rectangle<int>& rect)
  87. {
  88. if (! rect.isEmpty())
  89. {
  90. if (rects.size() == 0)
  91. {
  92. rects.add (rect);
  93. }
  94. else
  95. {
  96. bool anyOverlaps = false;
  97. int i;
  98. for (i = rects.size(); --i >= 0;)
  99. {
  100. Rectangle<int>& ourRect = rects.getReference (i);
  101. if (rect.intersects (ourRect))
  102. {
  103. if (rect.contains (ourRect))
  104. rects.remove (i);
  105. else if (! ourRect.reduceIfPartlyContainedIn (rect))
  106. anyOverlaps = true;
  107. }
  108. }
  109. if (anyOverlaps && rects.size() > 0)
  110. {
  111. RectangleList r (rect);
  112. for (i = rects.size(); --i >= 0;)
  113. {
  114. const Rectangle<int>& ourRect = rects.getReference (i);
  115. if (rect.intersects (ourRect))
  116. {
  117. r.subtract (ourRect);
  118. if (r.rects.size() == 0)
  119. return;
  120. }
  121. }
  122. for (i = r.getNumRectangles(); --i >= 0;)
  123. rects.add (r.rects.getReference (i));
  124. }
  125. else
  126. {
  127. rects.add (rect);
  128. }
  129. }
  130. }
  131. }
  132. void RectangleList::addWithoutMerging (const Rectangle<int>& rect)
  133. {
  134. if (! rect.isEmpty())
  135. rects.add (rect);
  136. }
  137. void RectangleList::add (const int x, const int y, const int w, const int h)
  138. {
  139. if (rects.size() == 0)
  140. {
  141. if (w > 0 && h > 0)
  142. rects.add (Rectangle<int> (x, y, w, h));
  143. }
  144. else
  145. {
  146. add (Rectangle<int> (x, y, w, h));
  147. }
  148. }
  149. void RectangleList::add (const RectangleList& other)
  150. {
  151. for (int i = 0; i < other.rects.size(); ++i)
  152. add (other.rects.getReference (i));
  153. }
  154. void RectangleList::subtract (const Rectangle<int>& rect)
  155. {
  156. const int originalNumRects = rects.size();
  157. if (originalNumRects > 0)
  158. {
  159. const int x1 = rect.x;
  160. const int y1 = rect.y;
  161. const int x2 = x1 + rect.w;
  162. const int y2 = y1 + rect.h;
  163. for (int i = getNumRectangles(); --i >= 0;)
  164. {
  165. Rectangle<int>& r = rects.getReference (i);
  166. const int rx1 = r.x;
  167. const int ry1 = r.y;
  168. const int rx2 = rx1 + r.w;
  169. const int ry2 = ry1 + r.h;
  170. if (! (x2 <= rx1 || x1 >= rx2 || y2 <= ry1 || y1 >= ry2))
  171. {
  172. if (x1 > rx1 && x1 < rx2)
  173. {
  174. if (y1 <= ry1 && y2 >= ry2 && x2 >= rx2)
  175. {
  176. r.w = x1 - rx1;
  177. }
  178. else
  179. {
  180. r.x = x1;
  181. r.w = rx2 - x1;
  182. rects.insert (i + 1, Rectangle<int> (rx1, ry1, x1 - rx1, ry2 - ry1));
  183. i += 2;
  184. }
  185. }
  186. else if (x2 > rx1 && x2 < rx2)
  187. {
  188. r.x = x2;
  189. r.w = rx2 - x2;
  190. if (y1 > ry1 || y2 < ry2 || x1 > rx1)
  191. {
  192. rects.insert (i + 1, Rectangle<int> (rx1, ry1, x2 - rx1, ry2 - ry1));
  193. i += 2;
  194. }
  195. }
  196. else if (y1 > ry1 && y1 < ry2)
  197. {
  198. if (x1 <= rx1 && x2 >= rx2 && y2 >= ry2)
  199. {
  200. r.h = y1 - ry1;
  201. }
  202. else
  203. {
  204. r.y = y1;
  205. r.h = ry2 - y1;
  206. rects.insert (i + 1, Rectangle<int> (rx1, ry1, rx2 - rx1, y1 - ry1));
  207. i += 2;
  208. }
  209. }
  210. else if (y2 > ry1 && y2 < ry2)
  211. {
  212. r.y = y2;
  213. r.h = ry2 - y2;
  214. if (x1 > rx1 || x2 < rx2 || y1 > ry1)
  215. {
  216. rects.insert (i + 1, Rectangle<int> (rx1, ry1, rx2 - rx1, y2 - ry1));
  217. i += 2;
  218. }
  219. }
  220. else
  221. {
  222. rects.remove (i);
  223. }
  224. }
  225. }
  226. }
  227. }
  228. bool RectangleList::subtract (const RectangleList& otherList)
  229. {
  230. for (int i = otherList.rects.size(); --i >= 0 && rects.size() > 0;)
  231. subtract (otherList.rects.getReference (i));
  232. return rects.size() > 0;
  233. }
  234. bool RectangleList::clipTo (const Rectangle<int>& rect)
  235. {
  236. bool notEmpty = false;
  237. if (rect.isEmpty())
  238. {
  239. clear();
  240. }
  241. else
  242. {
  243. for (int i = rects.size(); --i >= 0;)
  244. {
  245. Rectangle<int>& r = rects.getReference (i);
  246. if (! rect.intersectRectangle (r.x, r.y, r.w, r.h))
  247. rects.remove (i);
  248. else
  249. notEmpty = true;
  250. }
  251. }
  252. return notEmpty;
  253. }
  254. bool RectangleList::clipTo (const RectangleList& other)
  255. {
  256. if (rects.size() == 0)
  257. return false;
  258. RectangleList result;
  259. for (int j = 0; j < rects.size(); ++j)
  260. {
  261. const Rectangle<int>& rect = rects.getReference (j);
  262. for (int i = other.rects.size(); --i >= 0;)
  263. {
  264. Rectangle<int> r (other.rects.getReference (i));
  265. if (rect.intersectRectangle (r.x, r.y, r.w, r.h))
  266. result.rects.add (r);
  267. }
  268. }
  269. swapWith (result);
  270. return ! isEmpty();
  271. }
  272. bool RectangleList::getIntersectionWith (const Rectangle<int>& rect, RectangleList& destRegion) const
  273. {
  274. destRegion.clear();
  275. if (! rect.isEmpty())
  276. {
  277. for (int i = rects.size(); --i >= 0;)
  278. {
  279. Rectangle<int> r (rects.getReference (i));
  280. if (rect.intersectRectangle (r.x, r.y, r.w, r.h))
  281. destRegion.rects.add (r);
  282. }
  283. }
  284. return destRegion.rects.size() > 0;
  285. }
  286. void RectangleList::swapWith (RectangleList& otherList) noexcept
  287. {
  288. rects.swapWithArray (otherList.rects);
  289. }
  290. //==============================================================================
  291. void RectangleList::consolidate()
  292. {
  293. int i;
  294. for (i = 0; i < getNumRectangles() - 1; ++i)
  295. {
  296. Rectangle<int>& r = rects.getReference (i);
  297. const int rx1 = r.x;
  298. const int ry1 = r.y;
  299. const int rx2 = rx1 + r.w;
  300. const int ry2 = ry1 + r.h;
  301. for (int j = rects.size(); --j > i;)
  302. {
  303. Rectangle<int>& r2 = rects.getReference (j);
  304. const int jrx1 = r2.x;
  305. const int jry1 = r2.y;
  306. const int jrx2 = jrx1 + r2.w;
  307. const int jry2 = jry1 + r2.h;
  308. // if the vertical edges of any blocks are touching and their horizontals don't
  309. // line up, split them horizontally..
  310. if (jrx1 == rx2 || jrx2 == rx1)
  311. {
  312. if (jry1 > ry1 && jry1 < ry2)
  313. {
  314. r.h = jry1 - ry1;
  315. rects.add (Rectangle<int> (rx1, jry1, rx2 - rx1, ry2 - jry1));
  316. i = -1;
  317. break;
  318. }
  319. if (jry2 > ry1 && jry2 < ry2)
  320. {
  321. r.h = jry2 - ry1;
  322. rects.add (Rectangle<int> (rx1, jry2, rx2 - rx1, ry2 - jry2));
  323. i = -1;
  324. break;
  325. }
  326. else if (ry1 > jry1 && ry1 < jry2)
  327. {
  328. r2.h = ry1 - jry1;
  329. rects.add (Rectangle<int> (jrx1, ry1, jrx2 - jrx1, jry2 - ry1));
  330. i = -1;
  331. break;
  332. }
  333. else if (ry2 > jry1 && ry2 < jry2)
  334. {
  335. r2.h = ry2 - jry1;
  336. rects.add (Rectangle<int> (jrx1, ry2, jrx2 - jrx1, jry2 - ry2));
  337. i = -1;
  338. break;
  339. }
  340. }
  341. }
  342. }
  343. for (i = 0; i < rects.size() - 1; ++i)
  344. {
  345. Rectangle<int>& r = rects.getReference (i);
  346. for (int j = rects.size(); --j > i;)
  347. {
  348. if (r.enlargeIfAdjacent (rects.getReference (j)))
  349. {
  350. rects.remove (j);
  351. i = -1;
  352. break;
  353. }
  354. }
  355. }
  356. }
  357. //==============================================================================
  358. bool RectangleList::containsPoint (const int x, const int y) const noexcept
  359. {
  360. for (int i = getNumRectangles(); --i >= 0;)
  361. if (rects.getReference (i).contains (x, y))
  362. return true;
  363. return false;
  364. }
  365. bool RectangleList::containsRectangle (const Rectangle<int>& rectangleToCheck) const
  366. {
  367. if (rects.size() > 1)
  368. {
  369. RectangleList r (rectangleToCheck);
  370. for (int i = rects.size(); --i >= 0;)
  371. {
  372. r.subtract (rects.getReference (i));
  373. if (r.rects.size() == 0)
  374. return true;
  375. }
  376. }
  377. else if (rects.size() > 0)
  378. {
  379. return rects.getReference (0).contains (rectangleToCheck);
  380. }
  381. return false;
  382. }
  383. bool RectangleList::intersectsRectangle (const Rectangle<int>& rectangleToCheck) const noexcept
  384. {
  385. for (int i = rects.size(); --i >= 0;)
  386. if (rects.getReference (i).intersects (rectangleToCheck))
  387. return true;
  388. return false;
  389. }
  390. bool RectangleList::intersects (const RectangleList& other) const noexcept
  391. {
  392. for (int i = rects.size(); --i >= 0;)
  393. if (other.intersectsRectangle (rects.getReference (i)))
  394. return true;
  395. return false;
  396. }
  397. Rectangle<int> RectangleList::getBounds() const noexcept
  398. {
  399. if (rects.size() <= 1)
  400. {
  401. if (rects.size() == 0)
  402. return Rectangle<int>();
  403. else
  404. return rects.getReference (0);
  405. }
  406. else
  407. {
  408. const Rectangle<int>& r = rects.getReference (0);
  409. int minX = r.x;
  410. int minY = r.y;
  411. int maxX = minX + r.w;
  412. int maxY = minY + r.h;
  413. for (int i = rects.size(); --i > 0;)
  414. {
  415. const Rectangle<int>& r2 = rects.getReference (i);
  416. minX = jmin (minX, r2.x);
  417. minY = jmin (minY, r2.y);
  418. maxX = jmax (maxX, r2.getRight());
  419. maxY = jmax (maxY, r2.getBottom());
  420. }
  421. return Rectangle<int> (minX, minY, maxX - minX, maxY - minY);
  422. }
  423. }
  424. void RectangleList::offsetAll (const int dx, const int dy) noexcept
  425. {
  426. for (int i = rects.size(); --i >= 0;)
  427. {
  428. Rectangle<int>& r = rects.getReference (i);
  429. r.x += dx;
  430. r.y += dy;
  431. }
  432. }
  433. //==============================================================================
  434. Path RectangleList::toPath() const
  435. {
  436. Path p;
  437. for (int i = rects.size(); --i >= 0;)
  438. {
  439. const Rectangle<int>& r = rects.getReference (i);
  440. p.addRectangle ((float) r.x,
  441. (float) r.y,
  442. (float) r.w,
  443. (float) r.h);
  444. }
  445. return p;
  446. }
  447. END_JUCE_NAMESPACE