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.

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